Search code examples
c++thumbnailstifflibtiff

In a TIFF create a Sub IFD with thumbnail (libtiff)


I know thumbnail.c includes some code that creates a thumbnail and places it in a sub IDF, but there is a lot going on in that code (generating the thumbnail, applying a contrast curve, etc.) and I am having difficulty reproducing just writing a thumbnail. Google has not been any help either.

My question is, after I have opened an output file and have a TIFF*, I have my thumbnail data all ready to go (as well as my main image data), how do I add them in such a way that the thumbnail is in a sub IFD of the main image IFD?


Solution

  • So after digging around through the libtiff source code for a while, I stumbled across this in tif_dirwrite.c:

     /*
     * Copyright (c) 1988-1997 Sam Leffler
     * Copyright (c) 1991-1997 Silicon Graphics, Inc.
     *
     * Permission to use, copy, modify, distribute, and sell this software and
     * its documentation for any purpose is hereby granted without fee, provided
     * that (i) the above copyright notices and this permission notice appear in
     * all copies of the software and related documentation, and (ii) the names of
     * Sam Leffler and Silicon Graphics may not be used in any advertising or
     * publicity relating to the software without the specific, prior written
     * permission of Sam Leffler and Silicon Graphics.
     */
    
    ...
    if (!n)
        return(0);
    /*
     * Total hack: if this directory includes a SubIFD
     * tag then force the next <n> directories to be
     * written as ``sub directories'' of this one.  This
     * is used to write things like thumbnails and
     * image masks that one wants to keep out of the
     * normal directory linkage access mechanism.
     */
    tif->tif_flags|=TIFF_INSUBIFD;
    tif->tif_nsubifd=tif->tif_dir.td_nsubifd;
    if (tif->tif_dir.td_nsubifd==1)
        tif->tif_subifdoff=0;
    else
        tif->tif_subifdoff=m;
    return(1);
    ...
    

    (I included the copyright info because I wasn't sure if I had to when posting code from the library here)

    So, to answer my own question (how to write a thumbnail in a sub-IFD of the main image IFD):

    //...
    //For the sake of this demo we will assume that I have opened a 
    //TIFF (TIFF* created_TIFF) in write mode and have included the correct header
    //files
    
    //set all of your TIFF fields for the main image
    //...
    
    //Define the number of sub-IFDs you are going to write
    //(assuming here that we are only writing one thumbnail for the image):
    int number_of_sub_IFDs = 1;
    toff_t sub_IFDs_offsets[1] = { 0UL };
    
    //set the TIFFTAG_SUBIFD field:
    if(!TIFFSetField(created_TIFF, TIFFTAG_SUBIFD, number_of_sub_IFDs, 
        sub_IFDs_offsets))
    {
        //there was an error setting the field
    }
    
    //Write your main image raster data to the TIFF (using whatever means you need,
    //such as TIFFWriteRawStrip, TIFFWriteEncodedStrip, TIFFWriteEncodedTile, etc.)
    //...
    
    //Write your main IFD like so:
    TIFFWriteDirectory(created_TIFF);
    
    //Now here is the trick: like the comment in the libtiff source states, the 
    //next n directories written will be sub-IFDs of the main IFD (where n is 
    //number_of_sub_IFDs specified when you set the TIFFTAG_SUBIFD field)
    
    //Set up your sub-IFD
    if(!TIFFSetField(created_TIFF, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE))
    {
        //there was an error setting the field
    }
    
    //set the rest of the required tags here, as well as any extras you would like
    //(remember, these refer to the thumbnail, not the main image)
    //...
    
    //Write this sub-IFD:
    TIFFWriteDirectory(created_TIFF);
    
    //Assuming you are only writing one sub-IFD and are done with the file, you 
    //can close it now. If you specified more than one sub-IFD, you need repeat 
    //the above code (starting where we set TIFFTAG_SUBFILETYPE) for each of your
    //sub-IFDs
    TIFFClose(created_TIFF);
    

    I hope that this helps somebody and that they don't have to expend as much effort as I did to figure out how to do this. It really is a shame that libtiff is so poorly documented, especially considering how widely it is used.