2006.09.27 10:01 "[Tiff] help", by Robert Scheck

2006.10.11 10:21 "Re: [Tiff] Handling Of SubIFD in Libtiff Ver 3.8.3", by Sebastian Boehmer

Hello folks,

This Problem could be solved with the patch in the bugzilla report 1320
http://bugzilla.remotesensing.org/show_bug.cgi?id=1320

It add the following interface for private sub IFD support:
extern void TIFFMergePrivateFieldInfo(TIFF*, const TIFFFieldInfo[],unsigned int);

extern  const TIFFFieldInfo* TIFFFindPrivateFieldInfo(TIFF*, ttag_t, TIFFDataType);
extern  const TIFFFieldInfo* TIFFPrivateFieldWithTag(TIFF*, ttag_t);

extern  int TIFFSetPrivateField(TIFF*, ttag_t, ...);
extern  int TIFFVSetPrivateField(TIFF*, ttag_t, va_list);
extern  int TIFFGetPrivateField(TIFF*, ttag_t, ...);
extern  int TIFFVGetPrivateField(TIFF*, ttag_t, va_list);
extern  int TIFFWritePrivateDirectory(TIFF*, toff_t*);
extern  int TIFFReadPrivateDirectory(TIFF*, toff_t);
extern  int TIFFReadPrivateDirectoryWithFieldInfo(TIFF*, toff_t, const TIFFFieldInfo[], size_t);

In the attachment is an example Interface for the ATR private tags.
The code below comes from this files.
greets, Sebastian

Here is a draft of an example:

Use the code for custom tags from
http://www.remotesensing.org/libtiff/addingtags.html
The essenctial changes are marked with //!!!

 File: private_tags.h
---

#include <tiffio.h>

#include <tiff.h>

#define    TIFFTAG_PRIVATE_OFFSET       0xB10A  // !!!

//!!!

static const TIFFFieldInfo tiffIFDOffset[] = {

/* TIFF_IFD is actual not correct implemented in libtiff. */

        //{ TIFFTAG_PRIVATE_OFFSET, 1,1, TIFF_IFD,      FIELD_CUSTOM,

        //      TRUE, FALSE, "IMTEK ATR2 IFD" }
        /* BUG: libtiff 06-09-26: TIFF_IFD didn't work correct date:06-09-26 */

        { TIFFTAG_PRIVATE_OFFSET, 1,1, TIFF_LONG, FIELD_CUSTOM,
                TRUE, FALSE, "IMTEK ATR2 IFD" }
};

    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" }

};

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

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);
}

static void

_XTIFFDefaultDirectory(TIFF *tif)
{
    /* Install the extended Tag field info */

    TIFFMergeFieldInfo(tif, tiffIFDOffset, N(tiffIFDOffset));                   // !!!
    TIFFMergePrivateFieldInfo(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);
}

---

File: application.cc
---
#include <tiffio.h> // the libtiff

int main()
{

char filename[] = "test.tiff";
unsinged int length=100, width=100;
uint16 bps=8, spp=1;
unsigned char* imageBuffer = new unsigned char[2*length*width];

_XTIFFInitialize();
TIFF* image;
if (( image = TIFFOpen(filename,"w")) == NULL) {
        printf("Could not open %s for \n",filename);
        return -1;
}

        /*
        * Write the Image
        */
        // Check that it is of a type that we support

if(TIFFSetField(image, TIFFTAG_BITSPERSAMPLE, bps) == 0){ printf("Couldn't write the bits per sample. It is not possible to write the image."); TIFFClose(image);

        return -1;
}

if(TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL, spp) == 0){ printf("Couldn't write number of samples per pixel (last time %i)",spp); TIFFClose(image);

        return -1;
}
if(TIFFSetField(image, TIFFTAG_IMAGEWIDTH, width) == 0){
        printf("Couldn't write the width (last time %i)",width);
        TIFFClose(image);
        return -1;
}

... see attachment

/* write the image data */
if ( bps == 8 ) {
        if ( TIFFWriteEncodedStrip(image, 0, imageBuffer, width * length) == 0 ) {
                printf("Write error: TIFF image writing. \nPerhaps not enought memory?");
                TIFFClose(image);
                return -2;
        }

} else
        if ( TIFFWriteEncodedStrip(image, 0, imageBuffer, width * length * 2) == 0) {
                printf("Write error: TIFF image writing. \nPerhaps not enought memory?");
                TIFFClose(image);
                return -2;
        }

        /*
        * Write the Offset
        */
        // with pseudo value for calculating offset
        if (!TIFFSetField(image, TIFFTAG_PRIVATE_OFFSET, 0 ))

        printf("Couldn't write the offset tag to 0");
if (!TIFFCheckpointDirectory(image))
        printf("Couldn't write the checkpoint");
tiff_ifd_offset = TIFFCurrentDirOffset(image);

if (!TIFFSetField(image, TIFFTAGSPEC_OFFSET_V1, tiff_ifd_offset)) { printf("Couldn't write the offset tag (offset=%d)",TIFFCurrentDirOffset(image));

}
if (!TIFFWriteDirectory(image)) {
        printf("Couldn't write the directory");
        TIFFClose(image);
        return -5;
}

        /*
        * Write the private values
        */
        if (! TIFFSetPrivateField(image, TIFFTAG_GEOPIXELSCALE, 0.3 ) {

        printf("Error at writing private field\n");
        return -2;
}

...

        /*
        * Write the private Sub IFD
        */
        toff_t tiff_ref_offset = 0;
        if (!TIFFWritePrivateCustomDirectory(image,&tiff_ref_offset)) {

        printf("Couldn't write the custom directory\n");
        TIFFClose(image);
        return -8;
}

TIFFClose(image);

/*
 * now we read the file
 */

if ( (image = TIFFOpen(filename,"r")) == NULL ) {
        printf("Could not open %s for reading \n",filename);
        return -3;
}

/*
        * Get the Image
        */
// Check that it is of a type that we support

if((TIFFGetField(image, TIFFTAG_BITSPERSAMPLE, &bps) == 0) || !((bps == 8) || (bps == 16))){ printf("Either undefined or unsupported number of bits per sample (should be 8 or 16)"); TIFFClose(image);

        return -1;
}

if((TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &spp) == 0) || (spp != 1)){ printf("Either undefined or unsupported number of samples per pixel (should be 1)"); TIFFClose(image);

        return -1;
}

...

/* read the image */
for (row = 0; row < length; row++)
        if ( TIFFReadScanline(image, &imageBuffer[row*scanLineSize], row, 0) == -1 ) {
                sprintf(error_str,"Read error on input \nscanLineSize=%i row=%i",scanLineSize,row);
                setError(error_str);
                closeFile(image);
                return -1;
        }

...
        /*
         * Read the private subIFD
         */

toff_t tiff_ifd_offset;
// get the offset to the directory

if (! TIFFGetField(image, TIFFTAG_PRIVATE_OFFSET, &tiff_ifd_offset) ) { printf("Couldn't find the private IFD Offset to the ATR tags.");

        return -2;
}
// read directory from offset
if (! TIFFReadPrivateCustomDirectory(image, tiff_ifd_offset) ) {
        printf("Couldn't read the private ATR tags.");
        return -2;
}

        /*
        * Read the private values
        */

float f;

if (TIFFGetPrivateField(image, TIFFTAG_GEOPIXELSCALE, &f) == 0) { printf("Couldn't read the private value geo pixel scale");

        }
...

TIFFClose(image);

        return 0;
}