Defining New TIFF Tags

Libtiff has built-in knowledge of all the standard TIFF tags, as well as extentions. The following describes how to add knowledge of new tags as builtins to libtiff, or how to application specific tags can be used by applications without modifying libtiff.

TIFFFieldInfo

How libtiff manages specific tags is primarily controlled by the definition for that tag value stored internally as a TIFFFieldInfo structure. This structure looks like this:

typedef	struct {
  ttag_t    field_tag;          /* field's tag */
  short	    field_readcount;    /* read count/TIFF_VARIABLE/TIFF_SPP */
  short	    field_writecount;   /* write count/TIFF_VARIABLE */
  TIFFDataType field_type;      /* type of associated data */
  unsigned short field_bit;     /* bit in fieldsset bit vector */
  unsigned char field_oktochange;/* if true, can change while writing */
  unsigned char field_passcount;/* if true, pass dir count on set */
  char	*field_name;		/* ASCII name */
} TIFFFieldInfo;
A TIFFFieldInfo definition exists for each built-in tag in the tif_dirinfo.c file. Some tags which support multiple data types have more than one definition, one per data type supported.

Various functions exist for getting the internal TIFFFieldInfo definitions, including _TIFFFindFieldInfo(), and _TIFFFindFieldInfoByName(). See tif_dirinfo.c for details. There must be some mechanism to get the whole list, though I don't see it off hand.

Default Tag Auto-registration

In libtiff 3.6.0 a new mechanism was introduced allowing libtiff to read unrecognised tags automatically. When an unknown tags is encountered, it is automatically internally defined with a default name and a type derived from the tag value in the file. Applications only need to predefine application specific tags if they need to be able to set them in a file, or if particular calling conventions are desired for TIFFSetField() and TIFFGetField().

When tags are autodefined like this the field_readcount and field_writecount values are always TIFF_VARIABLE. The field_passcount is always TRUE, and the field_bit is FIELD_CUSTOM. The field name will be "Tag %d" where the %d is the tag number.

Defining Application Tags

For various reasons, it is common for applications to want to define their own tags to store information outside the core TIFF specification. This is done by calling TIFFMergeFieldInfo() with one or more TIFFFieldInfos.

The libgeotiff library provides geospatial information extentions within a TIFF file. First, a set of TIFFFieldInfo's is prepared with information on the new tags:

static const TIFFFieldInfo xtiffFieldInfo[] = {
  
  /* XXX Insert Your tags here */
    { TIFFTAG_GEOPIXELSCALE,	-1,-1, TIFF_DOUBLE,	FIELD_CUSTOM,
      TRUE,	TRUE,	"GeoPixelScale" },
    { TIFFTAG_GEOTRANSMATRIX,	-1,-1, TIFF_DOUBLE,	FIELD_CUSTOM,
      TRUE,	TRUE,	"GeoTransformationMatrix" },
    { TIFFTAG_GEOTIEPOINTS,	-1,-1, TIFF_DOUBLE,	FIELD_CUSTOM,
      TRUE,	TRUE,	"GeoTiePoints" },
    { TIFFTAG_GEOKEYDIRECTORY, -1,-1, TIFF_SHORT,	FIELD_CUSTOM,
      TRUE,	TRUE,	"GeoKeyDirectory" },
    { TIFFTAG_GEODOUBLEPARAMS,	-1,-1, TIFF_DOUBLE,	FIELD_CUSTOM,
      TRUE,	TRUE,	"GeoDoubleParams" },
    { TIFFTAG_GEOASCIIPARAMS,	-1,-1, TIFF_ASCII,	FIELD_CUSTOM,
      TRUE,	FALSE,	"GeoASCIIParams" }
};
In order to define the tags, we call TIFFMergeFieldInfo() on the desired TIFF handle with the list of TIFFFieldInfos.

#define	N(a)	(sizeof (a) / sizeof (a[0]))

    /* Install the extended Tag field info */
    TIFFMergeFieldInfo(tif, xtiffFieldInfo, N(xtiffFieldInfo));
The tags need to be defined for each TIFF file opened - and when reading they should be defined before the tags of the file are read, yet a valid TIFF * is needed to merge the tags against. In order to get them registered at the appropriate part of the setup process, it is necessary to register our merge function as an extender callback with libtiff. This is done with TIFFSetTagExtender(). We also keep track of the previous tag extender (if any) so that we can call it from our extender allowing a chain of customizations to take effect.

static TIFFExtendProc _ParentExtender = NULL;

static
void _XTIFFInitialize(void)
{
    static int first_time=1;
	
    if (! first_time) return; /* Been there. Done that. */
    first_time = 0;
	
    /* Grab the inherited method and install */
    _ParentExtender = TIFFSetTagExtender(_XTIFFDefaultDirectory);
}
The extender callback is looks like this. It merges in our new fields and then calls the next extender if there is one in effect.

static void
_XTIFFDefaultDirectory(TIFF *tif)
{
    /* Install the extended Tag field info */
    TIFFMergeFieldInfo(tif, xtiffFieldInfo, N(xtiffFieldInfo));

    /* Since an XTIFF client module may have overridden
     * the default directory method, we call it now to
     * allow it to set up the rest of its own methods.
     */

    if (_ParentExtender) 
        (*_ParentExtender)(tif);
}
The above approach ensures that our new definitions are used when reading or writing any TIFF file. However, since on reading we already have default definitions for tags, it is usually not critical to pre-define them. If tag definitions are only required for writing custom tags, you can just call TIFFMergeFieldInfo() before setting new tags. The whole extender architecture can then be avoided.

Adding New Builtin Tags

A similar approach is taken to the above. However, the TIFFFieldInfo should be added to the tiffFieldInfo[] list in tif_dirinfo.c. Ensure that new tags are added in sorted order by the tag number.

Normally new built-in tags should be defined with FIELD_CUSTOM; however, if it is desirable for the tag value to have it's own field in the TIFFDirectory structure, then you will need to #define a new FIELD_ value for it, and add appropriate handling as follows:

  1. Define the tag in tiff.h.
  2. Add a field to the directory structure in tif_dir.h and define a FIELD_* bit (also update the definition of FIELD_CODEC to reflect your addition).
  3. Add an entry in the TIFFFieldInfo array defined at the top of tif_dirinfo.c. Note that you must keep this array sorted by tag number and that the widest variant entry for a tag should come first (e.g. LONG before SHORT).
  4. Add entries in _TIFFVSetField() and _TIFFVGetField() for the new tag.
  5. (optional) If the value associated with the tag is not a scalar value (e.g. the array for TransferFunction) and requires special processing, then add the appropriate code to TIFFReadDirectory() and TIFFWriteDirectory(). You're best off finding a similar tag and cribbing code.
  6. Add support to TIFFPrintDirectory() in tif_print.c to print the tag's value.

If you want to maintain portability, beware of making assumptions about data types. Use the typedefs (uint16, etc. when dealing with data on disk and t*_t when stuff is in memory) and be careful about passing items through printf or similar vararg interfaces.

Adding New Codec-private Tags

To add tags that are meaningful only when a particular compression algorithm is used follow these steps:
  1. Define the tag in tiff.h.
  2. Allocate storage for the tag values in the private state block of the codec.
  3. Insure the state block is created when the codec is initialized.
  4. At TIFFInitfoo time override the method pointers in the TIFF structure for getting, setting and printing tag values. For example,
        sp->vgetparent = tif->tif_vgetfield;
        tif->tif_vgetfield = fooVGetField;	/* hook for codec tags */
        sp->vsetparent = tif->tif_vsetfield;
        tif->tif_vsetfield = fooVSetField;	/* hook for codec tags */
        tif->tif_printdir = fooPrintDir;	/* hook for codec tags */
    
    (Actually you may decide not to override the tif_printdir method, but rather just specify it).
  5. Create a private TIFFFieldInfo array for your tags and merge them into the core tags at initialization time using _TIFFMergeFieldInfo; e.g.
        _TIFFMergeFieldInfo(tif, fooFieldInfo, N(fooFieldInfo));
    
    (where N is a macro used liberaly throughout the distributed code).
  6. Fill in the get and set routines. Be sure to call the parent method for tags that you are not handled directly. Also be sure to set the FIELD_* bits for tags that are to be written to the file. Note that you can create ``pseudo-tags'' by defining tags that are processed exclusively in the get/set routines and never written to file (see the handling of TIFFTAG_FAXMODE in tif_fax3.c for an example of this).
  7. Fill in the print routine, if appropriate.
Note that space has been allocated in the FIELD_* bit space for codec-private tags. Define your bits as FIELD_CODEC+<offset> to keep them away from the core tags. If you need more tags than there is room for, just increase FIELD_SETLONGS at the top of tiffiop.h.
Last updated: $Date: 2004/09/10 14:43:18 $