roentgen b75cab
roentgen b75cab
roentgen b75cab
<title></title>
roentgen b75cab
Modifying The TIFF Library
roentgen b75cab
roentgen b75cab
roentgen b75cab
 
roentgen b75cab
<font face="Arial, Helvetica, Sans"></font>
roentgen b75cab
roentgen b75cab

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

roentgen b75cab
roentgen b75cab

TIFFFieldInfo

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

roentgen b75cab
roentgen b75cab
roentgen b75cab
typedef	struct {
roentgen b75cab
  ttag_t    field_tag;          /* field's tag */
roentgen b75cab
  short	    field_readcount;    /* read count/TIFF_VARIABLE/TIFF_SPP */
roentgen b75cab
  short	    field_writecount;   /* write count/TIFF_VARIABLE */
roentgen b75cab
  TIFFDataType field_type;      /* type of associated data */
roentgen b75cab
  unsigned short field_bit;     /* bit in fieldsset bit vector */
roentgen b75cab
  unsigned char field_oktochange;/* if true, can change while writing */
roentgen b75cab
  unsigned char field_passcount;/* if true, pass dir count on set */
roentgen b75cab
  char	*field_name;		/* ASCII name */
roentgen b75cab
} TIFFFieldInfo;
roentgen b75cab
roentgen b75cab
roentgen b75cab
    roentgen b75cab
  • field_tag: the tag number. For instance 277 for the
  • roentgen b75cab
    SamplesPerPixel tag.  Builtin tags will generally have a #define in
    roentgen b75cab
    tiff.h for each known tag. 

    roentgen b75cab
    roentgen b75cab
  • field_readcount: The number of values which should be read.
  • roentgen b75cab
    The special value TIFF_VARIABLE (-1) indicates that a variable number of
    roentgen b75cab
    values may be read.  The special value TIFFTAG_SPP (-2) indicates that there
    roentgen b75cab
    should be one value for each sample as defined by TIFFTAG_SAMPLESPERPIXEL.  
    roentgen b75cab
    The special value TIFF_VARIABLE2 (-3) is presumably similar to TIFF_VARIABLE
    roentgen b75cab
    though I am not sure what the distinction in behaviour is.  This field
    roentgen b75cab
    is TIFF_VARIABLE for variable length ascii fields.

    roentgen b75cab
    roentgen b75cab
  • field_writecount: The number of values which should be written.
  • roentgen b75cab
    Generally the same as field_readcount.  A few built-in exceptions exist, but
    roentgen b75cab
    I haven't analysed why they differ. 

    roentgen b75cab
    roentgen b75cab
  • field_type: Type of the field. One of TIFF_BYTE, TIFF_ASCII,
  • roentgen b75cab
    TIFF_SHORT, TIFF_LONG, TIFF_RATIONAL, TIFF_SBYTE, TIFF_UNDEFINED, 
    roentgen b75cab
    TIFF_SSHORT, TIFF_SLONG, TIFF_SRATIONAL, TIFF_FLOAT, TIFF_DOUBLE or
    roentgen b75cab
    TIFF_IFD.  Note that some fields can support more than one type (for 
    roentgen b75cab
    instance short and long).  These fields should have multiple TIFFFieldInfos. 
    roentgen b75cab

    roentgen b75cab
    roentgen b75cab
  • field_bit: Built-in tags stored in special fields in the
  • roentgen b75cab
    TIFF structure have assigned field numbers to distinguish them (ie. 
    roentgen b75cab
    FIELD_SAMPLESPERPIXEL).  New tags should generally just use 
    roentgen b75cab
    FIELD_CUSTOM indicating they are stored in the generic tag list.

    roentgen b75cab
    roentgen b75cab
  • field_oktochange: TRUE if it is OK to change this tag value
  • roentgen b75cab
    while an image is being written.  FALSE for stuff that must be set once
    roentgen b75cab
    and then left unchanged (like ImageWidth, or PhotometricInterpretation for
    roentgen b75cab
    instance).

    roentgen b75cab
    roentgen b75cab
  • field_passcount: If TRUE, then the count value must be passed
  • roentgen b75cab
    in TIFFSetField(), and TIFFGetField(), otherwise the count is not required.
    roentgen b75cab
    This should generally be TRUE for non-ascii variable count tags unless
    roentgen b75cab
    the count is implicit (such as with the colormap).

    roentgen b75cab
    roentgen b75cab
  • field_name: A name for the tag. Normally mixed case (studly caps)
  • roentgen b75cab
    like "StripByteCounts" and relatively short. 

    roentgen b75cab
    roentgen b75cab
    roentgen b75cab
    roentgen b75cab
    A TIFFFieldInfo definition exists for each built-in tag in the tif_dirinfo.c
    roentgen b75cab
    file.  Some tags which support multiple data types have more than one
    roentgen b75cab
    definition, one per data type supported. 

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

    roentgen b75cab
    roentgen b75cab

    Default Tag Auto-registration

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

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

    roentgen b75cab
    roentgen b75cab

    Defining Application Tags

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

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

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

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

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

    roentgen b75cab
    roentgen b75cab
    roentgen b75cab
    static void
    roentgen b75cab
    _XTIFFDefaultDirectory(TIFF *tif)
    roentgen b75cab
    {
    roentgen b75cab
        /* Install the extended Tag field info */
    roentgen b75cab
        TIFFMergeFieldInfo(tif, xtiffFieldInfo, N(xtiffFieldInfo));
    roentgen b75cab
    roentgen b75cab
        /* Since an XTIFF client module may have overridden
    roentgen b75cab
         * the default directory method, we call it now to
    roentgen b75cab
         * allow it to set up the rest of its own methods.
    roentgen b75cab
         */
    roentgen b75cab
    roentgen b75cab
        if (_ParentExtender) 
    roentgen b75cab
            (*_ParentExtender)(tif);
    roentgen b75cab
    }
    roentgen b75cab
    roentgen b75cab
    roentgen b75cab
    The above approach ensures that our new definitions are used when reading
    roentgen b75cab
    or writing any TIFF file.  However, since on reading we already have 
    roentgen b75cab
    default definitions for tags, it is usually not critical to pre-define them.
    roentgen b75cab
    If tag definitions are only required for writing custom tags, you can just
    roentgen b75cab
    call TIFFMergeFieldInfo() before setting new tags.  The whole extender
    roentgen b75cab
    architecture can then be avoided.

    roentgen b75cab
    roentgen b75cab

    Adding New Builtin Tags

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

    roentgen b75cab
    roentgen b75cab
    Normally new built-in tags should be defined with FIELD_CUSTOM; however, if
    roentgen b75cab
    it is desirable for the tag value to have it's own field in the TIFFDirectory
    roentgen b75cab
    structure, then you will need to #define a new FIELD_ value for it, and
    roentgen b75cab
    add appropriate handling as follows:
    roentgen b75cab
    roentgen b75cab
    roentgen b75cab
      roentgen b75cab
    1. Define the tag in tiff.h.
    2. roentgen b75cab
    3. Add a field to the directory structure in tif_dir.h
    4. roentgen b75cab
         and define a <tt>FIELD_*</tt> bit (also update the definition of
      roentgen b75cab
         <tt>FIELD_CODEC</tt> to reflect your addition).
      roentgen b75cab
    5. Add an entry in the <tt>TIFFFieldInfo</tt> array defined at the top of
    6. roentgen b75cab
         tif_dirinfo.c. 
      roentgen b75cab
         Note that you must keep this array sorted by tag
      roentgen b75cab
         number and that the widest variant entry for a tag should come
      roentgen b75cab
         first (e.g. <tt>LONG</tt> before <tt>SHORT</tt>).
      roentgen b75cab
    7. Add entries in <tt>_TIFFVSetField()</tt> and <tt>_TIFFVGetField()</tt>
    8. roentgen b75cab
         for the new tag.
      roentgen b75cab
    9. (optional) If the value associated with the tag is not a scalar value
    10. roentgen b75cab
         (e.g. the array for <tt>TransferFunction</tt>) and requires
      roentgen b75cab
         special processing,
      roentgen b75cab
         then add the appropriate code to <tt>TIFFReadDirectory()</tt> and
      roentgen b75cab
         <tt>TIFFWriteDirectory()</tt>.  You're best off finding a similar tag and
      roentgen b75cab
         cribbing code.
      roentgen b75cab
    11. Add support to <tt>TIFFPrintDirectory()</tt> in tif_print.c
    12. roentgen b75cab
          to print the tag's value.
      roentgen b75cab
      roentgen b75cab
      roentgen b75cab

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

      Adding New Codec-private Tags

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

        roentgen b75cab
        roentgen b75cab
        Last updated: $Date: 2004/09/10 14:43:18 $
        roentgen b75cab
        roentgen b75cab
        roentgen b75cab
        roentgen b75cab