AWARE [SYSTEMS]
AWare Systems, , Home TIFF and LibTiff Mailing List Archive

LibTiff Mailing List

TIFF and LibTiff Mailing List Archive
November 2012

Previous Thread
Next Thread

Previous by Thread
Next by Thread

Previous by Date
Next by Date

Contact

The TIFF Mailing List Homepage
Archive maintained by AWare Systems



New Datamatrix section



Valid HTML 4.01!



Thread

2012.11.24 00:09 "help writing thumbnails to TIFF file?", by Paul Heckbert
2012.11.24 00:46 "Re: help writing thumbnails to TIFF file?", by Joris Van Damme
2012.11.25 13:01 "Re: help writing thumbnails to TIFF file?", by Edward Lam
2012.11.25 15:08 "Re: help writing thumbnails to TIFF file?", by Joris Van Damme
2012.11.27 02:10 "Re: help writing thumbnails to TIFF file?", by Paul Heckbert
2012.11.27 03:25 "Re: help writing thumbnails to TIFF file?", by Bob Friesenhahn
2012.11.27 13:12 "Re: help writing thumbnails to TIFF file?", by Joris Van Damme
2012.11.27 14:38 "Re: help writing thumbnails to TIFF file?", by Olivier Paquet
2012.11.28 03:06 "Re: help writing thumbnails to TIFF file?", by Olivier Paquet
2012.12.08 04:35 "Re: help writing thumbnails to TIFF file?", by Paul Heckbert
2012.11.27 18:09 "Re: help writing thumbnails to TIFF file?", by Daniel Mccoy

2012.12.08 04:35 "Re: help writing thumbnails to TIFF file?", by Paul Heckbert

Olivier: thanks very much!  Although mysterious, your trick does  
indeed work.  I like its simplicity!

Daniel: thanks.  I helped talk Darwyn into interviewing at Pixar,  
years ago.  Small world!

Here's the final version of my test program.  I suggest this gets  
added to the contrib directory of the distribution, if others agree  
with it.

/* Write a test picture to a TIFF file, with thumbnail, using libtiff.
  *
  * Run "thumb" to write data in the order:
  *   primary image, IFD0, thumbnail image, IFD1.
  * Run "thumb -checkpoint" to use TIFFCheckpointDirectory to write in  
the order I'd prefer:
  *   IFD0, IFD1, thumbnail image, primary image.
  *
  * Some software finds the thumbnail in IFD1, e.g. "exiftool - 
htmldump thumb.tif"
  *
  * Paul Heckbert, 2012/11/15, 2012/12/7
  */

#ifdef _WIN32
   #include <windows.h>
#endif
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <tiffio.h>

/* write a picture that's a horizontal ramp in red, vertical ramp in  
green, and specified blue */

static void write_image(TIFF *tif, int nx, int ny, int blue) {
   uint8 *buf = _TIFFmalloc(nx*3);
   int x, y;

   assert(buf);
   for (y=0; y<ny; y++) {
     uint8 *p = buf;
     for (x=0; x<nx; x++) {
       *p++ = x*255/(nx-1);  /* r */
       *p++ = y*255/(ny-1);  /* g */
       *p++ = blue;
     }
     assert(TIFFWriteScanline(tif, buf, y, 0) != -1);
   }
   _TIFFfree(buf);
}

static void set_tags(TIFF *tif, int nx, int ny, int compression) {
   printf("set_tags %d %d %d\n", nx, ny, compression);
   assert(TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, nx));
   assert(TIFFSetField(tif, TIFFTAG_IMAGELENGTH, ny));
   assert(TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8));
   assert(TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB));
   /* set strip size not too big */
   assert(TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, 1000));
   assert(TIFFSetField(tif, TIFFTAG_COMPRESSION, compression));
   if (compression == COMPRESSION_LZW)
     assert(TIFFSetField(tif, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL));
   assert(TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT));
   assert(TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG));
   assert(TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3));
}

int main(int argc, char **argv) {
   int px = 640, py;  /* primary image size */
   int tx = 160, ty = 120;  /* thumbnail image size */
   char *filename = "thumb.tif";
   int i, checkpoint = 0;
   TIFF *tif;

   for (i=1; i<argc; i++) {
     if (argv[i][0] == '-') {
       if (strcmp(argv[i], "-checkpoint") == 0)
         checkpoint = 1;
       else {
         printf("Error: unknown arg (%s)\n", argv[i]);
         printf("Usage: %s [-checkpoint] [WIDTH]\n", argv[0]);
         return 1;
       }
     } else {
       px = atoi(argv[i]);
     }
   }
   py = px*3/4;
   assert(py>0);

   tif = TIFFOpen(filename, "w");
   assert(tif);

   if (checkpoint) {
     printf("checkpoint\n");
     set_tags(tif, px, py, COMPRESSION_LZW);
     /* write IFD0 (preliminary version) and create an empty IFD1 */
     assert(TIFFCheckpointDirectory(tif));
     assert(TIFFWriteDirectory(tif));
     /* about the Checkpoint,Write combo above:
      *   if you leave off the Checkpoint, you'll get errors like this  
on later SetDirectory:
      *     MissingRequired: TIFF directory is missing required  
"StripOffsets" field.
      *   if you leave off the Write, you'll get warnings like
      *     _TIFFVGetField: thumb.tif: Invalid tag "Predictor" (not  
supported by codec).
      *     plus a failed assertion on SetDirectory.
      * The trick of following Checkpoint by Write was suggested by  
Olivier Paquet.
      * Adding the Write causes the new directory to be cleared.
      */
     set_tags(tif, tx, ty, COMPRESSION_NONE);
     /* write IFD1 (preliminary version) and create an empty IFD2 */
     assert(TIFFCheckpointDirectory(tif));
     assert(TIFFWriteDirectory(tif));
     /* set current dir to IFD1 */
     assert(TIFFSetDirectory(tif, 1));
     /* write pixels of thumbnail (has blue in upper left) */
     write_image(tif, tx, ty, 255);
     /* rewrite IFD1 */
     assert(TIFFWriteDirectory(tif));
     /* set current dir to IFD0 */
     assert(TIFFSetDirectory(tif, 0));
     /* write pixels of primary image (has black in upper left) */
     write_image(tif, px, py, 0);
   } else {
     printf("nocheckpoint\n");
     set_tags(tif, px, py, COMPRESSION_LZW);
     /* write pixels of primary image (has black in upper left) */
     write_image(tif, px, py, 0);
     /* write IFD0 */
     assert(TIFFWriteDirectory(tif));
     set_tags(tif, tx, ty, COMPRESSION_NONE);
     /* write pixels of thumbnail (has blue in upper left) */
     write_image(tif, tx, ty, 255);
   }

   /* causes TIFFWriteDirectory to be called */
   TIFFClose(tif);
   return 0;
}

On 2012/11/27, at 10:06 PM, Olivier Paquet wrote:

> On Tue, Nov 27, 2012 at 9:38 AM, Olivier Paquet
> <olivier.paquet@gmail.com> wrote:
>>> My current hypothesis: TIFFCheckpointDirectory works fine if you're
>>> writing only one directory, but it's buggy when there are multiple
>>> directories.
>>
>> Quite possible. It works by keeping the directory in memory for
>> further checkpoints or the final write. Getting it to work with
>> multiple directories requires rereading them (with TIFFSetDirectory)
>> which is very different. It does look like it should work so it can't
>> be that far from actually working. I will try to find some time to
>> take a closer look.
>
> After trying a few ugly hacks in libtiff, I got an apparently valid
> file with both libtiff 3 and 4 by adding a TIFFWriteDirectory call
> after each of your TIFFCheckpointDirectory calls. The file looks good
> in tiffinfo and tiffdump, will split with tiffsplit and opens in KDE's
> viewer (okular) as two pages of different resolution. tiffdump shows
> the layout to be IFD0, IFD1, data for IFD1, data for IFD0. I don't
> know how future-proof this is but it at least appears to work for now,
> in this specific case. Oh and it even passes valgrind :)
>
> Olivier