2005.03.17 03:42 "[Tiff] libtiff and EXIF", by Ron

2005.03.17 16:00 "[Tiff] [PATCH] libtiff and EXIF", by Ron

I've been looking at what is required to parse exif data using libtiff, and it looks like surprisingly little. It was trivial to bypass enough sanity checks to easily get it to recognise and read the ExifIFD and auto register all the tags it found there. And not that much harder to get it to recognise a similar tiff'ette extracted from the APP1 section of a jpeg file with exif data and then fed to libtiff.

So the biggest question is how you all feel about supporting this from libtiff. Obviously TIFFFieldInfo for exif tags, if people wanted them,

It is intended the libtiff support it, or at least cleanly allow it. I was about to dive into this myself. Please post a clean patch against the libtiff CVS version to libtiff's bugzilla at "http://bugzilla.remotesensing.org/enter_bug.cgi?product=libtiff".

Ugh, sorry I'm spoiled by the Debian bts and hate having to log into these things and deal with text outside of vim. I've posted a patch to: http://people.debian.org/~ron/tiff

which adds the (perhaps I should say 'a' ;) basic mechanism to do what we want here. It's against the 3.7.2 tarball for now, I'll co from cvs tomorrow if its really already skewed that much.

To extract exif data from a tiff, something like the following example should now suffice:

    uint16  count;
    uint32 *exif_offset;

    if( TIFFGetField( tiff, TIFFTAG_EXIFIFD, &count, &exif_offset ) )
        TIFFSetIFD( tiff, *exif_offset );

        /* Dump all exif tags. */
        TIFFPrintDirectory( tiff, stdout );

        /* Fetch one individually */
        uint16 *iso_setting;

        if( TIFFGetField( tiff, 34855, &count, &iso_setting ) )
            printf("iso = %hu", iso_setting[ 0 ]);

To get it from a jpeg is a little more involved. First fetch the APP1 block (using libjpeg or anything else you please) from the file, this contains the exif data (if any). Rip off the 'Exif' marker and padding. This leaves you with a contiguous block of data beginning with a tiff header which is the bit to give to libtiff.

Feed that block of data to TIFFBasicOpen, by whatever mechanism you might otherwise use to send it to TIFFClientOpen. The only difference is that BasicOpen will not try to read the first dir for you, since these blocks usually don't contain several tags that ClientOpen (or rather ReadDirectory and tiff6.0) require for a normal image dir.

If BasicOpen returns you a valid TIFF*, you can call TIFFSetIFD(tif,8) to read the first directory of the block. This typically will contain some tiff tags that libtiff will already recognise and a TIFFTAG_EXIFIFD which you can now use exactly the same way as shown above.

Or put more simply, prepend:

    TIFF *tiff = TIFFBasicOpen( ... );

    if( tiff )
        TIFFSetIFD( tiff, 8 );

to the psuedo-code above.

I'm not done with all this yet, but its enough for today to prove it can be done, and there is plenty to run with for anyone interested who wants to chip in while I get a few hours sleep :-)