Package net.sourceforge.jiu.codecs
Class PNGCodec
- java.lang.Object
-
- net.sourceforge.jiu.ops.Operation
-
- net.sourceforge.jiu.codecs.ImageCodec
-
- net.sourceforge.jiu.codecs.PNGCodec
-
public class PNGCodec extends ImageCodec
A codec for the Portable Network Graphics (PNG) format. Supports both loading and saving of images.Usage examples
Load an image
The following example code loads an image from a PNG file. Note that you could also useImageLoader
orToolkitLoader
which require only a single line of code and can load all formats supported by JIU, including PNG.PNGCodec codec = new PNGCodec(); codec.setFile("image.png", CodecMode.LOAD); codec.process(); PixelImage image = codec.getImage();
Save an image
PNGCodec codec = new PNGCodec(); codec.setFile("out.png", CodecMode.SAVE); codec.setImage(image); codec.setCompressionLevel(Deflater.BEST_COMPRESSION); codec.appendComment("Copyright (c) 1992 John Doe"); // sets last modification time to current time codec.setModification(new GregorianCalendar( new SimpleTimeZone(0, "UTC"))); codec.process();
Supported storage order types
Loading
This codec reads both non-interlaced and Adam7 interlaced PNG files.Saving
This codec only writes non-interlaced PNG files.Supported color types
Loading
- Grayscale 1 bit streams are loaded as
BilevelImage
objects, 2, 4 and 8 bit streams asGray8Image
and 16 bit asGray16Image
objects. - Indexed 1, 2, 4 and 8 bit streams are all loaded as
Paletted8Image
. - RGB truecolor 24 bit streams are loaded as
RGB24Image
, 48 bit streams asRGB48Image
objects.
Saving
BilevelImage
objects are stored as grayscale 1 bit PNG streams.Paletted8Image
objects are stored as indexed 8 bit PNG streams. Images will always be stored as 8 bit files, even if the palette has only 16, 4 or 2 entries.Gray8Image
objects are stored as 8 bit grayscale PNG streams.Gray16Image
objects are stored as 16 bit grayscale PNG streams.RGB24Image
objects are stored as 24 bit RGB truecolor PNG streams.RGB48Image
objects are stored as 48 bit RGB truecolor PNG streams.
Transparency information
PNG allows to store different types of transparency information. Full alpha channels, transparent index values, and more. Right now, this JIU codec does not make use of this information and simply skips over it when encountered.Bounds
This codec regards the bounds concept. If bounds are specified withImageCodec.setBounds(int, int, int, int)
, the codec will only load or save part of an image.Metadata
Loading
- Physical resolution information is loaded from
pHYs
chunks. UseImageCodec.getDpiX()
andImageCodec.getDpiY()
to retrieve that information. after the call toprocess()
. - Textual comments are read from
tEXt
chunks and can be retrieved withImageCodec.getComment(int)
after the call toprocess()
.
Saving
- Physical resolution information (specified with
ImageCodec.setDpi(int, int)
) is stored in apHYs
chunk. - Textual comments (specified with
ImageCodec.appendComment(java.lang.String)
) are stored astEXt
chunks. The keyword used isComment
. Each of theImageCodec.getNumComments()
is stored in a chunk of its own. - Time of modification is stored in a
tIME
chunk. UsesetModification(Calendar)
to give a point in time to this codec.
Implementation details
This class relies heavily on the Java runtime library for decompression and checksum creation.Background
To learn more about the PNG file format, visit its official homepage. There you can find a detailed specification, test images and existing PNG libraries and PNG-aware applications. The book PNG - The Definitive Guide by Greg Roelofs, published by O'Reilly, 1999, ISBN 1-56592-542-4 is a valuable source of information on PNG. It is out of print, but it can be viewed online and downloaded for offline reading in its entirety from the site.- Since:
- 0.12.0
- Author:
- Marco Schmidt
- Grayscale 1 bit streams are loaded as
-
-
Field Summary
-
Constructor Summary
Constructors Constructor Description PNGCodec()
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description private void
allocateImage()
Allocates the right image to private fieldimage
, taking into consideration the fields width, height, precision and colorType.private void
checkColorTypeAndPrecision()
private int
computeBytesPerRow(int numPixels)
Computes a number of bytes for a given number of pixels, regarding precision and availability of an alpha channel.private int
computeColumnsAdam7(int pass)
private void
fillRowBuffer(int y, byte[] row, int offs)
private static String
getChunkName(int chunk)
Creates a four-letter String from the parameter, anint
value, supposed to be storing a chunk name.String
getFormatName()
Returns the name of the file format supported by this codec.String[]
getMimeTypes()
Return the MIME (Multipurpose Internet Mail Extensions) type strings for this format, ornull
if none are available.private static int
getPaeth(byte l, byte u, byte nw)
private void
inflateBytes(byte[] buffer, int numBytes)
boolean
isLoadingSupported()
Returns if this codec is able to load images in the file format supported by this codec.boolean
isSavingSupported()
Returns if this codec is able to save images in the file format supported by this codec.private void
load()
private void
loadChunk()
private void
loadImage(long chunkSize)
Load an image from the current position in the file.private void
loadImageHeader()
Reads data from an IHDR chunk and initializes private fields with it.private void
loadImageInterlacedAdam7()
private void
loadImageNonInterlaced()
private void
loadPalette(long numEntries)
static void
main(String[] args)
void
process()
This method does the actual work of the operation.private int
readFilterType()
private void
reverseFilter(int rowFilterType, byte[] buffer, byte[] prev, int numBytes)
private void
save()
private void
saveChunk(int chunkType, int chunkSize, byte[] data)
private void
saveIendChunk()
private void
saveIhdrChunk()
private void
saveImage()
private void
saveImageNonInterlaced()
private void
savePhysChunk()
private void
savePlteChunk()
private void
saveTextChunks()
private void
saveTimeChunk()
void
setCompressionLevel(int newLevel)
Sets the compression level to be used with the underlyingDeflater
object which does the compression.void
setCompressionStrategy(int newStrategy)
Sets the compression strategy to be used with the underlyingDeflater
object which does the compression.void
setEncodingIdatSize(int newSize)
Sets the size of IDAT chunks generated when encoding.void
setFile(String fileName, CodecMode codecMode)
Gives a file name and codec mode to the codec which will then try to create the corresponding I/O object.void
setModification(Calendar time)
Sets date and time of last modification of the image to be stored in a PNG stream when saving.private void
skip(long num)
Skips a number of bytes in the input stream.private void
storeInterlacedAdam7(int pass, int y, byte[] buffer)
private void
storeInterlacedAdam7Gray(int pass, int y, byte[] buffer)
private void
storeInterlacedAdam7GrayAlpha(int pass, int y, byte[] buffer)
private void
storeInterlacedAdam7Indexed(int pass, int y, byte[] buffer)
private void
storeInterlacedAdam7Rgb(int pass, int y, byte[] buffer)
private void
storeInterlacedAdam7RgbAlpha(int pass, int y, byte[] buffer)
private void
storeNonInterlaced(int y, byte[] buffer)
private void
storeNonInterlacedGray(int y, byte[] buffer)
private void
storeNonInterlacedGrayAlpha(int y, byte[] buffer)
private void
storeNonInterlacedIndexed(int y, byte[] buffer)
private void
storeNonInterlacedRgb(int y, byte[] buffer)
private void
storeNonInterlacedRgbAlpha(int y, byte[] buffer)
String
suggestFileExtension(PixelImage image)
Attempts to suggest a filename extension.-
Methods inherited from class net.sourceforge.jiu.codecs.ImageCodec
appendComment, checkBounds, checkImageResolution, close, getBoundsHeight, getBoundsWidth, getBoundsX1, getBoundsX2, getBoundsY1, getBoundsY2, getComment, getDataInput, getDataOutput, getDpiX, getDpiY, getFileExtensions, getImage, getImageIndex, getInputAsDataInput, getInputStream, getMode, getNumComments, getOutputAsDataOutput, getOutputStream, getRandomAccessFile, hasBounds, initModeFromIOObjects, isRowRequired, isTileRequired, removeAllComments, removeBounds, setBounds, setBoundsIfNecessary, setDataInput, setDataOutput, setDpi, setFile, setImage, setImageIndex, setInputStream, setOutputStream, setRandomAccessFile
-
Methods inherited from class net.sourceforge.jiu.ops.Operation
addProgressListener, addProgressListeners, getAbort, removeProgressListener, setAbort, setProgress, setProgress
-
-
-
-
Field Detail
-
CHUNK_CRC32_IEND
private final int CHUNK_CRC32_IEND
- See Also:
- Constant Field Values
-
CHUNK_SIZE_IHDR
private final int CHUNK_SIZE_IHDR
- See Also:
- Constant Field Values
-
CHUNK_TYPE_IDAT
private final int CHUNK_TYPE_IDAT
- See Also:
- Constant Field Values
-
CHUNK_TYPE_IEND
private final int CHUNK_TYPE_IEND
- See Also:
- Constant Field Values
-
CHUNK_TYPE_IHDR
private final int CHUNK_TYPE_IHDR
- See Also:
- Constant Field Values
-
CHUNK_TYPE_PHYS
private final int CHUNK_TYPE_PHYS
- See Also:
- Constant Field Values
-
CHUNK_TYPE_PLTE
private final int CHUNK_TYPE_PLTE
- See Also:
- Constant Field Values
-
CHUNK_TYPE_TEXT
private final int CHUNK_TYPE_TEXT
- See Also:
- Constant Field Values
-
CHUNK_TYPE_TIME
private final int CHUNK_TYPE_TIME
- See Also:
- Constant Field Values
-
COLOR_TYPE_GRAY
private final int COLOR_TYPE_GRAY
- See Also:
- Constant Field Values
-
COLOR_TYPE_GRAY_ALPHA
private final int COLOR_TYPE_GRAY_ALPHA
- See Also:
- Constant Field Values
-
COLOR_TYPE_INDEXED
private final int COLOR_TYPE_INDEXED
- See Also:
- Constant Field Values
-
COLOR_TYPE_RGB
private final int COLOR_TYPE_RGB
- See Also:
- Constant Field Values
-
COLOR_TYPE_RGB_ALPHA
private final int COLOR_TYPE_RGB_ALPHA
- See Also:
- Constant Field Values
-
COLOR_TYPE_ALPHA
private final int COLOR_TYPE_ALPHA
- See Also:
- Constant Field Values
-
FILTER_TYPE_NONE
private final int FILTER_TYPE_NONE
- See Also:
- Constant Field Values
-
FILTER_TYPE_SUB
private final int FILTER_TYPE_SUB
- See Also:
- Constant Field Values
-
FILTER_TYPE_UP
private final int FILTER_TYPE_UP
- See Also:
- Constant Field Values
-
FILTER_TYPE_AVERAGE
private final int FILTER_TYPE_AVERAGE
- See Also:
- Constant Field Values
-
FILTER_TYPE_PAETH
private final int FILTER_TYPE_PAETH
- See Also:
- Constant Field Values
-
COMPRESSION_DEFLATE
private final int COMPRESSION_DEFLATE
- See Also:
- Constant Field Values
-
INTERLACING_NONE
private final int INTERLACING_NONE
- See Also:
- Constant Field Values
-
INTERLACING_ADAM7
private final int INTERLACING_ADAM7
- See Also:
- Constant Field Values
-
FILTERING_ADAPTIVE
private final int FILTERING_ADAPTIVE
- See Also:
- Constant Field Values
-
MAX_TEXT_SIZE
private final int MAX_TEXT_SIZE
- See Also:
- Constant Field Values
-
ADAM7_NUM_PASSES
private final int ADAM7_NUM_PASSES
- See Also:
- Constant Field Values
-
DEFAULT_ENCODING_MIN_IDAT_SIZE
private final int DEFAULT_ENCODING_MIN_IDAT_SIZE
- See Also:
- Constant Field Values
-
ADAM7_COLUMN_INCREMENT
private final int[] ADAM7_COLUMN_INCREMENT
-
ADAM7_FIRST_COLUMN
private final int[] ADAM7_FIRST_COLUMN
-
ADAM7_FIRST_ROW
private final int[] ADAM7_FIRST_ROW
-
ADAM7_ROW_INCREMENT
private final int[] ADAM7_ROW_INCREMENT
-
MAGIC_BYTES
private final byte[] MAGIC_BYTES
-
alpha
private boolean alpha
-
buffers
private byte[][] buffers
-
bpp
private int bpp
-
checksum
private CRC32 checksum
-
checkedIn
private CheckedInputStream checkedIn
-
chunkCounter
private int chunkCounter
-
colorType
private int colorType
-
compressionType
private int compressionType
-
currentBufferIndex
private int currentBufferIndex
-
deflateLevel
private int deflateLevel
-
deflateStrategy
private int deflateStrategy
-
encodingMinIdatSize
private int encodingMinIdatSize
-
filterType
private int filterType
-
hasIhdr
private boolean hasIhdr
-
height
private int height
-
image
private IntegerImage image
-
in
private DataInputStream in
-
infl
private InflaterInputStream infl
-
interlaceType
private int interlaceType
-
modification
private Calendar modification
-
numChannels
private int numChannels
-
out
private DataOutput out
-
palette
private Palette palette
-
precision
private int precision
-
previousBufferIndex
private int previousBufferIndex
-
width
private int width
-
-
Method Detail
-
allocateImage
private void allocateImage() throws InvalidFileStructureException, UnsupportedTypeException
Allocates the right image to private fieldimage
, taking into consideration the fields width, height, precision and colorType. Assumes that an IHDR chunk has been read and the above mentioned fields have been initialized and checked for their validity.
-
checkColorTypeAndPrecision
private void checkColorTypeAndPrecision() throws UnsupportedTypeException
Checks valuesprecision
andcolorType
. A lot of combinations possibly found in an IHDR chunk are invalid. Also initializesalpha
andnumChannels
.- Throws:
UnsupportedTypeException
- if an invalid combination of precision and colorType is found
-
computeBytesPerRow
private int computeBytesPerRow(int numPixels)
Computes a number of bytes for a given number of pixels, regarding precision and availability of an alpha channel.- Parameters:
numPixels
- the number of pixels for which the number of bytes necessary to store them is to be computed- Returns:
- number of bytes
-
computeColumnsAdam7
private int computeColumnsAdam7(int pass)
-
fillRowBuffer
private void fillRowBuffer(int y, byte[] row, int offs)
-
getChunkName
private static String getChunkName(int chunk)
Creates a four-letter String from the parameter, anint
value, supposed to be storing a chunk name.- Returns:
- the chunk name
-
getFormatName
public String getFormatName()
Description copied from class:ImageCodec
Returns the name of the file format supported by this codec. All classes extendingImageCodec
must override this method. When overriding, leave out any words in a particular language so that this format name can be understood by everyone. Usually it is enough to return the format creator plus a typical abbreviation, e.g.Microsoft BMP
orPortable Anymap (PNM)
.- Specified by:
getFormatName
in classImageCodec
- Returns:
- name of the file format supported by this codec
-
getMimeTypes
public String[] getMimeTypes()
Description copied from class:ImageCodec
Return the MIME (Multipurpose Internet Mail Extensions) type strings for this format, ornull
if none are available.- Specified by:
getMimeTypes
in classImageCodec
- Returns:
- MIME type strings or null
-
getPaeth
private static int getPaeth(byte l, byte u, byte nw)
-
inflateBytes
private void inflateBytes(byte[] buffer, int numBytes) throws InvalidFileStructureException, IOException
-
isLoadingSupported
public boolean isLoadingSupported()
Description copied from class:ImageCodec
Returns if this codec is able to load images in the file format supported by this codec. Iftrue
is returned this does not necessarily mean that all files in this format can be read, but at least some.- Specified by:
isLoadingSupported
in classImageCodec
- Returns:
- if loading is supported
-
isSavingSupported
public boolean isSavingSupported()
Description copied from class:ImageCodec
Returns if this codec is able to save images in the file format supported by this codec. Iftrue
is returned this does not necessarily mean that all types files in this format can be written, but at least some.- Specified by:
isSavingSupported
in classImageCodec
- Returns:
- if saving is supported
-
load
private void load() throws InvalidFileStructureException, IOException, UnsupportedTypeException, WrongFileFormatException
-
loadChunk
private void loadChunk() throws InvalidFileStructureException, IOException, UnsupportedTypeException
-
loadImage
private void loadImage(long chunkSize) throws InvalidFileStructureException, IOException, UnsupportedTypeException
Load an image from the current position in the file. Assumes the last things read from input are an IDAT chunk type and its size, which is the sole argument of this method.- Parameters:
chunkSize
- size of the IDAT chunk that was just read- Throws:
InvalidFileStructureException
- if there are values in the PNG stream that make it invalidIOException
- if there were I/O errors when readingUnsupportedTypeException
- if something was encountered in the stream that is valid but not supported by this codec
-
loadImageHeader
private void loadImageHeader() throws IOException, InvalidFileStructureException, UnsupportedTypeException
Reads data from an IHDR chunk and initializes private fields with it. Does a lot of checking if read values are valid and supported by this class.
-
loadImageInterlacedAdam7
private void loadImageInterlacedAdam7() throws InvalidFileStructureException, IOException, UnsupportedTypeException
-
loadImageNonInterlaced
private void loadImageNonInterlaced() throws InvalidFileStructureException, IOException, UnsupportedTypeException
-
loadPalette
private void loadPalette(long numEntries) throws InvalidFileStructureException, IOException
-
process
public void process() throws InvalidFileStructureException, MissingParameterException, OperationFailedException, UnsupportedTypeException, WrongFileFormatException
Description copied from class:Operation
This method does the actual work of the operation. It must be called after all parameters have been given to the operation object.- Overrides:
process
in classOperation
- Throws:
MissingParameterException
- if any mandatory parameter was not given to the operationWrongParameterException
- if at least one of the input parameters was not initialized appropriately (values out of the valid interval, etc.)OperationFailedException
InvalidFileStructureException
UnsupportedTypeException
WrongFileFormatException
-
readFilterType
private int readFilterType() throws InvalidFileStructureException, IOException
-
reverseFilter
private void reverseFilter(int rowFilterType, byte[] buffer, byte[] prev, int numBytes) throws UnsupportedTypeException
- Throws:
UnsupportedTypeException
-
save
private void save() throws IOException
- Throws:
IOException
-
saveChunk
private void saveChunk(int chunkType, int chunkSize, byte[] data) throws IOException
- Throws:
IOException
-
saveIendChunk
private void saveIendChunk() throws IOException
- Throws:
IOException
-
saveIhdrChunk
private void saveIhdrChunk() throws IOException
- Throws:
IOException
-
saveImage
private void saveImage() throws IOException
- Throws:
IOException
-
saveImageNonInterlaced
private void saveImageNonInterlaced() throws IOException
- Throws:
IOException
-
savePhysChunk
private void savePhysChunk() throws IOException
- Throws:
IOException
-
savePlteChunk
private void savePlteChunk() throws IOException
- Throws:
IOException
-
saveTextChunks
private void saveTextChunks() throws IOException
- Throws:
IOException
-
saveTimeChunk
private void saveTimeChunk() throws IOException
- Throws:
IOException
-
setCompressionLevel
public void setCompressionLevel(int newLevel)
Sets the compression level to be used with the underlyingDeflater
object which does the compression. If no value is specified,Deflater.DEFAULT_COMPRESSION
is used.- Parameters:
newLevel
- compression level, from 0 to 9, 0 being fastest and compressing worst and 9 offering highest compression and taking the most time
-
setCompressionStrategy
public void setCompressionStrategy(int newStrategy)
Sets the compression strategy to be used with the underlyingDeflater
object which does the compression. If no value is specified,Deflater.DEFAULT_STRATEGY
is used.- Parameters:
newStrategy
- one of Deflater's strategy values:Deflater.DEFAULT_STRATEGY
,Deflater.FILTERED
,Deflater.HUFFMAN_ONLY
-
setEncodingIdatSize
public void setEncodingIdatSize(int newSize)
Sets the size of IDAT chunks generated when encoding. If this method is never called, a default value of 32768 bytes (32 KB) is used. Note that a byte array of the size of the value you specify here is allocated, so make sure that you keep the value small enough to stay within a system's memory.Compressed image data is spread over several IDAT chunks by this codec. The length of the compressed data of a complete image is known only after the complete image has been encoded. With PNG, that length value has to be stored before the compressed data as a chunk size value. This codec is supposed to work with
OutputStream
objects, so seeking back to adjust the chunk size value of an IDAT chunk is not possible. That's why all data of a chunk is compressed into a memory buffer. Whenever the buffer gets full, it is written to output as an IDAT chunk.Note that the last IDAT chunk may be smaller than the size defined here.
- Parameters:
newSize
- size of encoding compressed data buffer
-
setFile
public void setFile(String fileName, CodecMode codecMode) throws IOException, UnsupportedCodecModeException
Description copied from class:ImageCodec
Gives a file name and codec mode to the codec which will then try to create the corresponding I/O object. The default implementation in ImageCodec creates a DataInputStream object wrapped around a BufferedInputStream wrapped around a FileInputStream for CodecMode.LOAD. Similar for CodecMode.SAVE: a DataOutputStream around a BufferedOutputStream object around a FileOutputStream object. Codecs that need different I/O objects must override this method (some codecs may need random access and thus require a RandomAccessFile object).- Overrides:
setFile
in classImageCodec
- Parameters:
fileName
- name of the file to be used for loading or savingcodecMode
- defines whether file is to be used for loading or saving- Throws:
IOException
UnsupportedCodecModeException
-
setModification
public void setModification(Calendar time)
Sets date and time of last modification of the image to be stored in a PNG stream when saving. Make sure the argument object has UTC as time zone (as demanded by the PNG specs). If you want the current time and date, usenew GregorianCalendar(new SimpleTimeZone(0, "UTC"))
as parameter for this method.- Parameters:
time
- time of last modification of the image
-
skip
private void skip(long num) throws IOException
Skips a number of bytes in the input stream.- Parameters:
num
- number of bytes to be skipped- Throws:
IOException
- if there were I/O errors
-
storeInterlacedAdam7
private void storeInterlacedAdam7(int pass, int y, byte[] buffer)
-
storeInterlacedAdam7Gray
private void storeInterlacedAdam7Gray(int pass, int y, byte[] buffer)
-
storeInterlacedAdam7GrayAlpha
private void storeInterlacedAdam7GrayAlpha(int pass, int y, byte[] buffer)
-
storeInterlacedAdam7Indexed
private void storeInterlacedAdam7Indexed(int pass, int y, byte[] buffer)
-
storeInterlacedAdam7Rgb
private void storeInterlacedAdam7Rgb(int pass, int y, byte[] buffer)
-
storeInterlacedAdam7RgbAlpha
private void storeInterlacedAdam7RgbAlpha(int pass, int y, byte[] buffer)
-
storeNonInterlaced
private void storeNonInterlaced(int y, byte[] buffer)
-
storeNonInterlacedGray
private void storeNonInterlacedGray(int y, byte[] buffer)
-
storeNonInterlacedGrayAlpha
private void storeNonInterlacedGrayAlpha(int y, byte[] buffer)
-
storeNonInterlacedIndexed
private void storeNonInterlacedIndexed(int y, byte[] buffer)
-
storeNonInterlacedRgb
private void storeNonInterlacedRgb(int y, byte[] buffer)
-
storeNonInterlacedRgbAlpha
private void storeNonInterlacedRgbAlpha(int y, byte[] buffer)
-
suggestFileExtension
public String suggestFileExtension(PixelImage image)
Description copied from class:ImageCodec
Attempts to suggest a filename extension. The type of the argument image will be taken into consideration, although this will be necessary for some file formats only (as an example, PNM has different extensions for different image types, seePNMCodec
). This default implementation always returnsnull
.- Overrides:
suggestFileExtension
in classImageCodec
- Parameters:
image
- the image that is to be written to a file- Returns:
- the file extension, including a leading dot, or
null
if no file extension can be recommended
-
-