A codec to read Tagged Image File Format (TIFF) image files.
Usage example
Load an image from a TIFF file.
TIFFCodec codec = new TIFFCodec();
codec.setFile("image.tif", CodecMode.LOAD);
codec.process();
PixelImage loadedImage = codec.getImage();
Saving images is not supported by this codec.
Compression types
Reading
The TIFF package supports the following compression types when reading:
- Uncompressed. Compression method number 1. Works with all types of image data. See
TIFFDecoderUncompressed
. - Packbits. Compression method number 32773. Works with all types of image data. See
TIFFDecoderPackbits
. - CCITT Group 3 1-Dimensional Modified Huffman runlength encoding. Compression method number 2.
Works with bilevel image data only. See
TIFFDecoderModifiedHuffman
. - Deflated. Compression method number 8 or 32946. Works with all types of image data. See
TIFFDecoderDeflated
. - LogLuv RLE and LogLuv 24. Compression method numbers 34676 and 34677. Works only with LogLuv color data. See
TIFFDecoderLogLuv
.
Note that you can write your own decoder (extending
TIFFDecoder
) for any compression type
you want.
Image types
Reading
The TIFF package supports the following image / color types when reading:
- Black & white. JIU image data type
BilevelImage
. - Grayscale, 4 and 8 bits per pixel. JIU image data type
Gray8Image
. - TODO add other image types
Note that you can write your own decoder (extending
TIFFDecoder
) for any compression type
you want.
Writing
Writing TIFFs is not supported.
I don't know if or when it will be supported.
Strips and tiles
The early versions of TIFF considered an image to be a sequence of
strips.
Each strip was a rectangular part of the image, as wide as the complete image,
and with a certain height defined by the
rows per strip tag.
So with a number of rows per strip of 10, and an image height of 200, you would
have to store 20 strips.
It was recommended that a strip should not be larger than 8 KB (RAM was tighter
in those days).
The rule of thumb to define the number of rows per strip was to see how many rows
would fit into 8 KB.
Later, the concept of
tiles was added to the TIFF specs.
Tiled TIFFs are separated into rectangles that not only had a defineable
height but also a defineable width (tile width and tile height are also stored in
corresponding tags).
Obviously, strips are just a special case of tiles, with the tile width being equal
to image width.
That is why JIU internally only deals with tiles.
The only difference: No row padding takes place for strips.
In a tiled image with a tile height of 10 and an image height of 14,
the image is two tiles high.
Number of images
TIFF allows for multiple images in a single file.
This codec regards the image index, queries
TIFFCodec
and skips to the
correct image.
Bounds
The bounds concept of JIU is supported by this codec.
So you can specify bounds of a rectangular part of an image that you want to load
instead of loading the complete image.
Color spaces
The following color spaces are understood when reading truecolor TIFF files.
- RGB - should cover most truecolor files.
- CMYK - is supported, but colors may not be exactly right.
CMYK data is converted to RGB on the fly, so the codec user never accesses CMYK data.
- LogLuv - is supported, but not all flavors yet.
Physical resolution
DPI information can be stored in TIFF files.
If that information is available, this codec retrieves it so that it
can be queried using
TIFFCodec
and
TIFFCodec
.
Background information on TIFF
TIFF is an important image file format for DTP (desktop publishing).
The advantages of TIFF include its flexibility, availability of libraries to read
and write TIFF files and its good support in existing software.
The major disadvantage of TIFF is its complexity, which makes it hard for software
to support all possible valid TIFF files.
TIFF was created by Aldus and now
belongs to Adobe, who offer a specification document:
TIFF
(Tagged Image File Format) 6.0 Specification (updated on Web September, 20 1995,
document dated June, 3 1992) (PDF: 385 KB / 121 pages).
Other good references include the
homepage
of libtiff, a free C library to read and write TIFF files and
The Unofficial TIFF
homepage by Niles Ritter.
Also see
the TIFF section
of the
Open Directory.
TIFF is used for various specialized tasks.
As an example, see
GeoTIFF (geographical
data) or
EXIF
(digital camera metadata; this is actually a TIFF directory embedded in a JPEG header).
Here's a list of features that make TIFF quite complex:
- More than one image can be stored in a TIFF file.
- Integer values that are larger than one byte can be in either little or big endian byte order.
- Various color types are supported (bilevel, gray, paletted, all kinds of color spaces (RGB / YCbCr / CMYK).
It's easy to add new color types, so this list can grow.
- The meta data (information that describes the image and how it is stored) can be distributed all over
the file.
- Image data is stored as packed bytes, 4-bit-nibbles, bytes and 16-bit-integers. Other types are possible
as well.
- Various compression types are supported; not all types can be used on all color types.
- Image data can be stored in strips or tiles.
- An arbitrary number of non-image-data samples can stored within the image data.
- Color types with more than one sample per pixel can store data in an interleaved (chunky)
way or in planes.
- Different ways of defining black and white are possible with bilevel and grayscale images.
adjustInt
private int adjustInt(int value,
int type)
If the current byte order is
BYTE_ORDER_MOTOROLA
and the type
argument is
TiffConstants.TAG_TYPE_BYTE
or
TiffConstants.TAG_TYPE_SHORT
, the value parameter must
be adjusted by some bitshifting.
If the above mentioned criteria are not met, the value argument is
returned without any modifications.
Why this is necessary remains a mystery to me. Marco
value
- the int value which may have to be adjusted
- the value parameter which may have been modified
getByteOrder
public int getByteOrder()
getTagName
public static String getTagName(int id)
Returns the name of a tag in English.
id
- of the tag for which a name is to be returned
- tag name as String or a question mark
?
readHeader
private void readHeader()
throws IOException,
WrongFileFormatException
Reads the first eight bytes from the input file, checks if this is a
valid TIFF file and stores byte order and offset of the first image
file directory.
readImageFileDirectory
private TIFFImageFileDirectory readImageFileDirectory()
throws InvalidFileStructureException,
IOException
Reads a complete TIFF image file directory including all data that is
pointed to using the offset components and returns it.
- the image file directory data or
null
on failure
readInt
private int readInt()
throws IOException
Reads a 32 bit signed integer value, regarding the current byte order.
readShort
private short readShort()
throws IOException
Reads a 16 bit signed integer value, regarding the current byte order.
readString
private String readString(int length)
throws IOException
Loads a String of a given length from current position of input file.
Characters are one-byte ASCII.
Non-text characters are dropped.
length
- number of characters in a row to be loaded
readTag
private TIFFTag readTag()
throws InvalidFileStructureException,
IOException
Reads a TIFF tag and all data belonging to it and returns a
TIFFTag object.
The additional data is somewhere in the TIFF file.
The current position will be stored, the method will seek to the offset
position and load the data.
- TIFFTag containing information on the tag
registerDecoder
public static void registerDecoder(Class decoderClass)
Register a
TIFFDecoder
class.
TIFF knows many compression types, and JIU only supports some of them.
To register an external TIFFDecoder class with TIFFCodec, call this method
with the class field of your decoder.
As an example, for your TIFFDecoderMyCompression class,
call
TIFFCodec.registerDecoder(TIFFDecoderMyCompression.class)
.
It will be checked if
decoderClass.newInstance() instanceof TIFFDecoder
is true and, if so, the class will be added to an internal list.
Whenever a TIFF file is to be decoded, the correct decoder is determined
(each decoder knows about the compression types it supports via the getCompressionTypes method)
and for each tile or strip such a decoder object will be created.
setByteOrder
private void setByteOrder(int newByteOrder)
newByteOrder
- the new byte order to be set
skipImageFileDirectories
private void skipImageFileDirectories(int numDirectories)
throws InvalidFileStructureException,
IOException
Skips a given number of image file directories in this TIFF files.
Throws an exception if there were errors or not enough image file
directories.
numDirectories
- the number of directories to be skipped,
should be non-negative