- 2012.11.23 23:49 "Re: [Tiff] Write Exif data to Tiff file", by Paul Heckbert
- 2012.11.24 00:46 "Re: [Tiff] help writing thumbnails to TIFF file?", by Joris Van Damme
- 2012.11.27 02:10 "Re: [Tiff] help writing thumbnails to TIFF file?", by Paul Heckbert
- 2012.12.08 04:35 "Re: [Tiff] help writing thumbnails to TIFF file?", by Paul Heckbert
2012.11.24 00:09 "[Tiff] help writing thumbnails to TIFF file?", by Paul Heckbert
I reported this (with subject TIFFCheckpointDirectory not working when
writing two IFDs) a week ago at bugzilla
(http://bugzilla.maptools.org/show_bug.cgi?id=2417) but have not heard a
reply, so I'll try here.
I am trying to use libtiff to create a TIFF file that contains two IFDs, one
for the primary image and one for a small thumbnail image. I'd like the
order of data in the TIFF file to be IFD0, IFD1, thumbnail image, primary
image -- that would be most consistent with other image creation software,
e.g. Photoshop. Surely this should be possible with libtiff.
The attached C code is a pretty minimal demonstration of the problem. If
run with no arguments, it results in two warnings
_TIFFVGetField: thumb.tif: Invalid tag "Predictor" (not supported by codec).
_TIFFVGetField: thumb.tif: Invalid tag "Predictor" (not supported by codec).
and then crashes with
thumb.c:68: failed assertion `TIFFSetDirectory(tif, 1)'
Abort trap
and if I examine the partially-written output file with exiftool, it shows
that IFD1 was written directly on top of IFD0 - this is not what I wanted
and probably explains the Predictor messages.
The man page for TIFFCheckpointDirectory is sketchy, as is much of libtiff's
documentation. There is no discussion of how TIFFWriteDirectory or
TIFFCheckpointDirectory increment the current directory index, although
examination of the source code makes that clear, making it a challenge for
anyone trying to write multiple IFDs with any control over the order of data
in the file. And I don't find any example uses of TIFFCheckpointDirectory
in the tools/ or contrib/ dirs, so consequently I am only able to guess that
I'm using TIFFCheckpointDirectory and TIFFSetDirectory properly.
Either there's a bug in TIFFCheckpointDirectory or I am using that function
incorrectly. Which is it?
I'm on Mac OS 10.5.8 and linking with libtiff 4.0.3.
thumb.c:
---
/* Write a test picture to a TIFF file, with thumbnail and EXIF, using
libtiff.
*
- Run "thumb -nocheckpoint" to write data in the order:
- primary image, IFD0, thumbnail image, IFD1.
- and most software (e.g. Mac Finder, exiftool) does not find IFD1, it seems.
- With no args, this program uses TIFFCheckpointDirectory to write in the order I'd prefer:
- IFD0, IFD1, thumbnail image, primary image.
- But running it this way causes IFD1 to overwrite IFD0
- and gives an assert on the first call to TIFFSetDirectory.
*
* Paul Heckbert, 2012/11/15
*/
#include <assert.h>
#include <string.h>
#include <tiffio.h>
static void write_image(TIFF *tif, int nx, int ny) {
uint8 *buf = _TIFFmalloc(nx*3);
int x, y;
assert(buf);
/* picture has horizontal ramp in red, vertical ramp in green */
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++ = 0; /* b */
}
assert(TIFFWriteScanline(tif, buf, y, 0) != -1);
}
_TIFFfree(buf);
}
static void set_tags(TIFF *tif, int nx, int ny, int 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));
assert(TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, ny)); /* one strip */ printf("set_tags %d %d %d\n", nx, ny, compression); 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 = 480; /* primary image size */
int tx = 160, ty = 120; /* thumbnail image size */
char *filename = "thumb.tif";
int checkpoint = argc!=2 || strcmp(argv[1], "-nocheckpoint");
TIFF *tif = TIFFOpen(filename, "w");
assert(tif);
if (checkpoint) {
set_tags(tif, px, py, COMPRESSION_LZW);
/* write IFD0 (preliminary version) and create an empty IFD1 */
assert(TIFFCheckpointDirectory(tif));
set_tags(tif, tx, ty, COMPRESSION_NONE);
/* write IFD1 (preliminary version) and create an empty IFD2 */
assert(TIFFCheckpointDirectory(tif));
/* set current dir to IFD1 */
assert(TIFFSetDirectory(tif, 1));
/* write pixels of thumbnail */
write_image(tif, tx, ty);
/* write IFD1 */
assert(TIFFWriteDirectory(tif));
/* set current dir to IFD0 */
assert(TIFFSetDirectory(tif, 0));
/* write pixels of primary image */
write_image(tif, px, py);
} else {
set_tags(tif, px, py, COMPRESSION_LZW);
/* write pixels of primary image */
write_image(tif, px, py);
/* write IFD0 */
assert(TIFFWriteDirectory(tif));
set_tags(tif, tx, ty, COMPRESSION_NONE);
/* write pixels of thumbnail */
write_image(tif, tx, ty);
}
/* causes TIFFWriteDirectory to be called */
TIFFClose(tif);
return 0;
}
---
Makefile
---
DEP = ../../../dependencies
TIFF = $(DEP)/tiff-4.0.3/build
COPTS = -g -Wall -Werror
TIFF_DYLIB = $(TIFF)/lib/libtiff.dylib
thumb: thumb.o $(TIFF_DYLIB)
gcc $(COPTS) -o $@ $^ $(TIFF_DYLIB)
.c.o:
gcc -c $(COPTS) -I$(TIFF)/include $<
---
--
View this message in context: http://old.nabble.com/help-writing-thumbnails-to-TIFF-file--tp34716184p34716184.html
Sent from the Tiff / LibTiff mailing list archive at Nabble.com.