9 tiff.c - implements reading and writing tiff files, uses io layer.
13 io_glue *ig = io_new_fd( fd );
14 i_img *im = i_readtiff_wiol(ig, -1); // no limit on how much is read
16 io_glue *ig = io_new_fd( fd );
17 return_code = i_writetiff_wiol(im, ig);
21 tiff.c implements the basic functions to read and write tiff files.
22 It uses the iolayer and needs either a seekable source or an entire
25 =head1 FUNCTION REFERENCE
27 Some of these functions are internal.
35 #define byteswap_macro(x) \
36 ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
37 (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
44 static struct tag_name text_tag_names[] =
46 { "tiff_documentname", TIFFTAG_DOCUMENTNAME, },
47 { "tiff_imagedescription", TIFFTAG_IMAGEDESCRIPTION, },
48 { "tiff_make", TIFFTAG_MAKE, },
49 { "tiff_model", TIFFTAG_MODEL, },
50 { "tiff_pagename", TIFFTAG_PAGENAME, },
51 { "tiff_software", TIFFTAG_SOFTWARE, },
52 { "tiff_datetime", TIFFTAG_DATETIME, },
53 { "tiff_artist", TIFFTAG_ARTIST, },
54 { "tiff_hostcomputer", TIFFTAG_HOSTCOMPUTER, },
57 static const int text_tag_count =
58 sizeof(text_tag_names) / sizeof(*text_tag_names);
60 static void error_handler(char const *module, char const *fmt, va_list ap) {
61 i_push_errorvf(0, fmt, ap);
64 static void warn_handler(char const *module, char const *fmt, va_list ap) {
65 /* for now do nothing, perhaps we could warn(), though that should be
66 done in the XS code, not in the code which isn't mean to know perl
70 static int save_tiff_tags(TIFF *tif, i_img *im);
72 static void expand_4bit_hl(unsigned char *buf, int count);
74 static void pack_4bit_hl(unsigned char *buf, int count);
77 static toff_t sizeproc(thandle_t x) {
83 =item comp_seek(h, o, w)
85 Compatability for 64 bit systems like latest freebsd (internal)
87 h - tiff handle, cast an io_glue object
96 comp_seek(thandle_t h, toff_t o, int w) {
97 io_glue *ig = (io_glue*)h;
98 return (toff_t) ig->seekcb(ig, o, w);
102 =item comp_mmap(thandle_t, tdata_t*, toff_t*)
106 This shouldn't ever be called but newer tifflibs want it anyway.
113 comp_mmap(thandle_t h, tdata_t*p, toff_t*off) {
118 =item comp_munmap(thandle_t h, tdata_t p, toff_t off)
122 This shouldn't ever be called but newer tifflibs want it anyway.
128 comp_munmap(thandle_t h, tdata_t p, toff_t off) {
132 static i_img *read_one_tiff(TIFF *tif) {
134 uint32 width, height;
136 uint32* raster = NULL;
140 int gotXres, gotYres;
142 uint16 bits_per_sample;
148 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
149 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
150 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &channels);
151 tiled = TIFFIsTiled(tif);
152 TIFFGetFieldDefaulted(tif, TIFFTAG_PHOTOMETRIC, &photometric);
153 TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
155 mm_log((1, "i_readtiff_wiol: width=%d, height=%d, channels=%d\n", width, height, channels));
156 mm_log((1, "i_readtiff_wiol: %stiled\n", tiled?"":"not "));
157 mm_log((1, "i_readtiff_wiol: %sbyte swapped\n", TIFFIsByteSwapped(tif)?"":"not "));
159 if (photometric == PHOTOMETRIC_PALETTE && bits_per_sample <= 8) {
161 im = i_img_pal_new(width, height, channels, 256);
164 im = i_img_empty_ch(NULL, width, height, channels);
170 /* resolution tags */
171 TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
172 gotXres = TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres);
173 gotYres = TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres);
174 if (gotXres || gotYres) {
179 if (resunit == RESUNIT_CENTIMETER) {
180 /* from dots per cm to dpi */
184 i_tags_addn(&im->tags, "tiff_resolutionunit", 0, resunit);
185 if (resunit == RESUNIT_NONE)
186 i_tags_addn(&im->tags, "i_aspect_only", 0, 1);
187 i_tags_set_float(&im->tags, "i_xres", 0, xres);
188 i_tags_set_float(&im->tags, "i_yres", 0, yres);
192 for (i = 0; i < text_tag_count; ++i) {
194 if (TIFFGetField(tif, text_tag_names[i].tag, &data)) {
195 mm_log((1, "i_readtiff_wiol: tag %d has value %s\n",
196 text_tag_names[i].tag, data));
197 i_tags_add(&im->tags, text_tag_names[i].name, 0, data,
202 i_tags_add(&im->tags, "i_format", 0, "tiff", -1, 0);
204 /* TIFFPrintDirectory(tif, stdout, 0); good for debugging */
206 if (photometric == PHOTOMETRIC_PALETTE &&
207 (bits_per_sample == 4 || bits_per_sample == 8)) {
212 unsigned char *buffer;
214 if (!TIFFGetField(tif, TIFFTAG_COLORMAP, maps+0, maps+1, maps+2)) {
215 i_push_error(0, "Cannot get colormap for paletted image");
219 buffer = (unsigned char *)_TIFFmalloc(width+2);
221 i_push_error(0, "out of memory");
226 memset(used, 0, sizeof(used));
227 while (row < height && TIFFReadScanline(tif, buffer, row, 0) > 0) {
228 if (bits_per_sample == 4)
229 expand_4bit_hl(buffer, (width+1)/2);
230 for (col = 0; col < width; ++col) {
231 used[buffer[col]] = 1;
233 i_ppal(im, 0, width, row, buffer);
239 /* Ideally we'd optimize the palette, but that could be expensive
240 since we'd have to re-index every pixel.
242 Optimizing the palette (even at this level) might not
243 be what the user wants, so I don't do it.
245 We'll add a function to optimize a paletted image instead.
247 maxused = (1 << bits_per_sample)-1;
249 while (maxused >= 0 && !used[maxused])
252 for (i = 0; i < 1 << bits_per_sample; ++i) {
254 for (ch = 0; ch < 3; ++ch) {
255 c.channel[ch] = Sample16To8(maps[ch][i]);
257 i_addcolors(im, &c, 1);
265 uint32 tile_width, tile_height;
267 TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width);
268 TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height);
269 mm_log((1, "i_readtiff_wiol: tile_width=%d, tile_height=%d\n", tile_width, tile_height));
271 raster = (uint32*)_TIFFmalloc(tile_width * tile_height * sizeof (uint32));
274 i_push_error(0, "No space for raster buffer");
278 for( row = 0; row < height; row += tile_height ) {
279 for( col = 0; ok && col < width; col += tile_width ) {
280 uint32 i_row, x, newrows, newcols;
282 /* Read the tile into an RGBA array */
283 if (!TIFFReadRGBATile(tif, col, row, raster)) {
287 newrows = (row+tile_height > height) ? height-row : tile_height;
288 mm_log((1, "i_readtiff_wiol: newrows=%d\n", newrows));
289 newcols = (col+tile_width > width ) ? width-row : tile_width;
290 for( i_row = 0; i_row < tile_height; i_row++ ) {
291 for(x = 0; x < newcols; x++) {
293 uint32 temp = raster[x+tile_width*(tile_height-i_row-1)];
294 val.rgba.r = TIFFGetR(temp);
295 val.rgba.g = TIFFGetG(temp);
296 val.rgba.b = TIFFGetB(temp);
297 val.rgba.a = TIFFGetA(temp);
298 i_ppix(im, col+x, row+i_row, &val);
304 uint32 rowsperstrip, row;
305 int rc = TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
306 mm_log((1, "i_readtiff_wiol: rowsperstrip=%d rc = %d\n", rowsperstrip, rc));
308 if (rc != 1 || rowsperstrip==-1) {
309 rowsperstrip = height;
312 raster = (uint32*)_TIFFmalloc(width * rowsperstrip * sizeof (uint32));
315 i_push_error(0, "No space for raster buffer");
319 for( row = 0; row < height; row += rowsperstrip ) {
320 uint32 newrows, i_row;
322 if (!TIFFReadRGBAStrip(tif, row, raster)) {
327 newrows = (row+rowsperstrip > height) ? height-row : rowsperstrip;
328 mm_log((1, "newrows=%d\n", newrows));
330 for( i_row = 0; i_row < newrows; i_row++ ) {
332 for(x = 0; x<width; x++) {
334 uint32 temp = raster[x+width*(newrows-i_row-1)];
335 val.rgba.r = TIFFGetR(temp);
336 val.rgba.g = TIFFGetG(temp);
337 val.rgba.b = TIFFGetB(temp);
338 val.rgba.a = TIFFGetA(temp);
339 i_ppix(im, x, i_row+row, &val);
346 mm_log((1, "i_readtiff_wiol: error during reading\n"));
347 i_tags_addn(&im->tags, "i_incomplete", 0, 1);
356 =item i_readtiff_wiol(im, ig)
361 i_readtiff_wiol(io_glue *ig, int length) {
363 TIFFErrorHandler old_handler;
364 TIFFErrorHandler old_warn_handler;
368 old_handler = TIFFSetErrorHandler(error_handler);
369 old_warn_handler = TIFFSetWarningHandler(warn_handler);
371 /* Add code to get the filename info from the iolayer */
372 /* Also add code to check for mmapped code */
374 io_glue_commit_types(ig);
375 mm_log((1, "i_readtiff_wiol(ig %p, length %d)\n", ig, length));
377 tif = TIFFClientOpen("(Iolayer)",
380 (TIFFReadWriteProc) ig->readcb,
381 (TIFFReadWriteProc) ig->writecb,
382 (TIFFSeekProc) comp_seek,
383 (TIFFCloseProc) ig->closecb,
384 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
385 (TIFFMapFileProc) comp_mmap,
386 (TIFFUnmapFileProc) comp_munmap);
389 mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
390 i_push_error(0, "opening file");
391 TIFFSetErrorHandler(old_handler);
392 TIFFSetWarningHandler(old_warn_handler);
396 im = read_one_tiff(tif);
398 if (TIFFLastDirectory(tif)) mm_log((1, "Last directory of tiff file\n"));
399 TIFFSetErrorHandler(old_handler);
400 TIFFSetWarningHandler(old_warn_handler);
406 =item i_readtiff_multi_wiol(ig, length, *count)
408 Reads multiple images from a TIFF.
413 i_readtiff_multi_wiol(io_glue *ig, int length, int *count) {
415 TIFFErrorHandler old_handler;
416 TIFFErrorHandler old_warn_handler;
417 i_img **results = NULL;
418 int result_alloc = 0;
422 old_handler = TIFFSetErrorHandler(error_handler);
423 old_warn_handler = TIFFSetWarningHandler(warn_handler);
425 /* Add code to get the filename info from the iolayer */
426 /* Also add code to check for mmapped code */
428 io_glue_commit_types(ig);
429 mm_log((1, "i_readtiff_wiol(ig %p, length %d)\n", ig, length));
431 tif = TIFFClientOpen("(Iolayer)",
434 (TIFFReadWriteProc) ig->readcb,
435 (TIFFReadWriteProc) ig->writecb,
436 (TIFFSeekProc) comp_seek,
437 (TIFFCloseProc) ig->closecb,
438 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
439 (TIFFMapFileProc) comp_mmap,
440 (TIFFUnmapFileProc) comp_munmap);
443 mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
444 i_push_error(0, "opening file");
445 TIFFSetErrorHandler(old_handler);
446 TIFFSetWarningHandler(old_warn_handler);
452 i_img *im = read_one_tiff(tif);
455 if (++*count > result_alloc) {
456 if (result_alloc == 0) {
458 results = mymalloc(result_alloc * sizeof(i_img *));
463 newresults = myrealloc(results, result_alloc * sizeof(i_img *));
465 i_img_destroy(im); /* don't leak it */
468 results = newresults;
471 results[*count-1] = im;
472 } while (TIFFSetDirectory(tif, ++dirnum));
474 TIFFSetWarningHandler(old_warn_handler);
475 TIFFSetErrorHandler(old_handler);
481 i_writetiff_low_faxable(TIFF *tif, i_img *im, int fine) {
482 uint32 width, height;
483 unsigned char *linebuf = NULL;
489 float vres = fine ? 196 : 98;
495 switch (im->channels) {
505 /* This means a colorspace we don't handle yet */
506 mm_log((1, "i_writetiff_wiol_faxable: don't handle %d channel images.\n", im->channels));
510 /* Add code to get the filename info from the iolayer */
511 /* Also add code to check for mmapped code */
514 mm_log((1, "i_writetiff_wiol_faxable: width=%d, height=%d, channels=%d\n", width, height, im->channels));
516 if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width) )
517 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField width=%d failed\n", width)); return 0; }
518 if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height) )
519 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField length=%d failed\n", height)); return 0; }
520 if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1))
521 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField samplesperpixel=1 failed\n")); return 0; }
522 if (!TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT))
523 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Orientation=topleft\n")); return 0; }
524 if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 1) )
525 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField bitpersample=1\n")); return 0; }
526 if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG))
527 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField planarconfig\n")); return 0; }
528 if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK))
529 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField photometric=%d\n", PHOTOMETRIC_MINISBLACK)); return 0; }
530 if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, 3))
531 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField compression=3\n")); return 0; }
533 linebuf = (unsigned char *)_TIFFmalloc( TIFFScanlineSize(tif) );
535 if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, -1))) {
536 mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField rowsperstrip=-1\n")); return 0; }
538 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
539 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rc);
541 mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField rowsperstrip=%d\n", rowsperstrip));
542 mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField scanlinesize=%d\n", TIFFScanlineSize(tif) ));
543 mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG));
545 if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)204))
546 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Xresolution=204\n")); return 0; }
547 if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, vres))
548 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Yresolution=196\n")); return 0; }
549 if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH)) {
550 mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField ResolutionUnit=%d\n", RESUNIT_INCH)); return 0;
553 if (!save_tiff_tags(tif, im)) {
557 for (y=0; y<height; y++) {
559 for(x=0; x<width; x+=8) {
564 linebuf[linebufpos]=0;
565 bits = width-x; if(bits>8) bits=8;
566 i_gsamp(im, x, x+8, y, luma, &luma_chan, 1);
567 for(bitpos=0;bitpos<bits;bitpos++) {
568 linebuf[linebufpos] |= ((luma[bitpos]>=128)?bitval:0);
573 if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
574 mm_log((1, "i_writetiff_wiol_faxable: TIFFWriteScanline failed.\n"));
578 if (linebuf) _TIFFfree(linebuf);
584 i_writetiff_low(TIFF *tif, i_img *im) {
585 uint32 width, height;
587 uint16 predictor = 0;
589 int jpegcolormode = JPEGCOLORMODE_RGB;
590 uint16 compression = COMPRESSION_PACKBITS;
593 uint32 rowsperstrip = (uint32) -1; /* Let library pick default */
594 unsigned char *linebuf = NULL;
599 int got_xres, got_yres, got_aspectonly, aspect_only, resunit;
601 uint16 bitspersample = 8;
602 uint16 samplesperpixel;
603 uint16 *colors = NULL;
607 channels = im->channels;
611 photometric = PHOTOMETRIC_MINISBLACK;
614 photometric = PHOTOMETRIC_RGB;
615 if (compression == COMPRESSION_JPEG && jpegcolormode == JPEGCOLORMODE_RGB) photometric = PHOTOMETRIC_YCBCR;
616 else if (im->type == i_palette_type) {
617 photometric = PHOTOMETRIC_PALETTE;
621 /* This means a colorspace we don't handle yet */
622 mm_log((1, "i_writetiff_wiol: don't handle %d channel images.\n", channels));
626 /* Add code to get the filename info from the iolayer */
627 /* Also add code to check for mmapped code */
629 /*io_glue_commit_types(ig);*/
630 /*mm_log((1, "i_writetiff_wiol(im 0x%p, ig 0x%p)\n", im, ig));*/
632 mm_log((1, "i_writetiff_low: width=%d, height=%d, channels=%d\n", width, height, channels));
634 if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width) ) {
635 mm_log((1, "i_writetiff_wiol: TIFFSetField width=%d failed\n", width));
638 if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height) ) {
639 mm_log((1, "i_writetiff_wiol: TIFFSetField length=%d failed\n", height));
642 if (!TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT)) {
643 mm_log((1, "i_writetiff_wiol: TIFFSetField Orientation=topleft\n"));
646 if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) {
647 mm_log((1, "i_writetiff_wiol: TIFFSetField planarconfig\n"));
650 if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric)) {
651 mm_log((1, "i_writetiff_wiol: TIFFSetField photometric=%d\n", photometric));
654 if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, compression)) {
655 mm_log((1, "i_writetiff_wiol: TIFFSetField compression=%d\n", compression));
658 samplesperpixel = channels;
659 if (photometric == PHOTOMETRIC_PALETTE) {
662 int count = i_colorcount(im);
672 size = 1 << bitspersample;
673 colors = (uint16 *)_TIFFmalloc(sizeof(uint16) * 3 * size);
675 out[1] = colors + size;
676 out[2] = colors + 2 * size;
678 for (i = 0; i < count; ++i) {
679 i_getcolors(im, i, &c, 1);
680 for (ch = 0; ch < 3; ++ch)
681 out[ch][i] = c.channel[ch] * 257;
683 for (; i < size; ++i) {
684 for (ch = 0; ch < 3; ++ch)
687 if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitspersample)) {
688 mm_log((1, "i_writetiff_wiol: TIFFSetField bitpersample=%d\n",
692 if (!TIFFSetField(tif, TIFFTAG_COLORMAP, out[0], out[1], out[2])) {
693 mm_log((1, "i_writetiff_wiol: TIFFSetField colormap\n"));
698 if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitspersample)) {
699 mm_log((1, "i_writetiff_wiol: TIFFSetField bitpersample=%d\n",
704 if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel)) {
705 mm_log((1, "i_writetiff_wiol: TIFFSetField samplesperpixel=%d failed\n", samplesperpixel));
709 switch (compression) {
710 case COMPRESSION_JPEG:
711 mm_log((1, "i_writetiff_wiol: jpeg compression\n"));
712 if (!TIFFSetField(tif, TIFFTAG_JPEGQUALITY, quality) ) {
713 mm_log((1, "i_writetiff_wiol: TIFFSetField jpegquality=%d\n", quality));
716 if (!TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, jpegcolormode)) {
717 mm_log((1, "i_writetiff_wiol: TIFFSetField jpegcolormode=%d\n", jpegcolormode));
721 case COMPRESSION_LZW:
722 mm_log((1, "i_writetiff_wiol: lzw compression\n"));
724 case COMPRESSION_DEFLATE:
725 mm_log((1, "i_writetiff_wiol: deflate compression\n"));
727 if (!TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor)) {
728 mm_log((1, "i_writetiff_wiol: TIFFSetField predictor=%d\n", predictor));
732 case COMPRESSION_PACKBITS:
733 mm_log((1, "i_writetiff_wiol: packbits compression\n"));
736 mm_log((1, "i_writetiff_wiol: unknown compression %d\n", compression));
740 linebytes = channels * width;
741 linebytes = TIFFScanlineSize(tif) > linebytes ? linebytes
742 : TIFFScanlineSize(tif);
743 /* working space for the scanlines - we go from 8-bit/pixel to 4 */
744 if (photometric == PHOTOMETRIC_PALETTE && bitspersample == 4)
745 linebytes += linebytes + 1;
746 linebuf = (unsigned char *)_TIFFmalloc(linebytes);
748 if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, rowsperstrip))) {
749 mm_log((1, "i_writetiff_wiol: TIFFSetField rowsperstrip=%d\n", rowsperstrip)); return 0; }
751 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
752 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rc);
754 mm_log((1, "i_writetiff_wiol: TIFFGetField rowsperstrip=%d\n", rowsperstrip));
755 mm_log((1, "i_writetiff_wiol: TIFFGetField scanlinesize=%d\n", TIFFScanlineSize(tif) ));
756 mm_log((1, "i_writetiff_wiol: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG));
757 mm_log((1, "i_writetiff_wiol: bitspersample = %d\n", bitspersample));
759 got_xres = i_tags_get_float(&im->tags, "i_xres", 0, &xres);
760 got_yres = i_tags_get_float(&im->tags, "i_yres", 0, &yres);
761 if (!i_tags_get_int(&im->tags, "i_aspect_only", 0,&aspect_only))
763 if (!i_tags_get_int(&im->tags, "tiff_resolutionunit", 0, &resunit))
764 resunit = RESUNIT_INCH;
765 if (got_xres || got_yres) {
771 resunit = RESUNIT_NONE;
774 if (resunit == RESUNIT_CENTIMETER) {
779 resunit = RESUNIT_INCH;
782 if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)xres)) {
783 i_push_error(0, "cannot set TIFFTAG_XRESOLUTION tag");
786 if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)yres)) {
787 i_push_error(0, "cannot set TIFFTAG_YRESOLUTION tag");
790 if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (uint16)resunit)) {
791 i_push_error(0, "cannot set TIFFTAG_RESOLUTIONUNIT tag");
796 if (!save_tiff_tags(tif, im)) {
800 if (photometric == PHOTOMETRIC_PALETTE) {
801 for (y = 0; y < height; ++y) {
802 i_gpal(im, 0, width, y, linebuf);
803 if (bitspersample == 4)
804 pack_4bit_hl(linebuf, width);
805 if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
806 mm_log((1, "i_writetiff_wiol: TIFFWriteScanline failed.\n"));
807 if (linebuf) _TIFFfree(linebuf);
808 if (colors) _TIFFfree(colors);
814 for (y=0; y<height; y++) {
816 for(x=0; x<width; x++) {
817 (void) i_gpix(im, x, y,&val);
818 for(ch=0; ch<channels; ch++)
819 linebuf[ci++] = val.channel[ch];
821 if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
822 mm_log((1, "i_writetiff_wiol: TIFFWriteScanline failed.\n"));
823 if (linebuf) _TIFFfree(linebuf);
824 if (colors) _TIFFfree(colors);
829 if (linebuf) _TIFFfree(linebuf);
830 if (colors) _TIFFfree(colors);
835 =item i_writetiff_multi_wiol(ig, imgs, count, fine_mode)
837 Stores an image in the iolayer object.
839 ig - io_object that defines source to write to
840 imgs,count - the images to write
846 i_writetiff_multi_wiol(io_glue *ig, i_img **imgs, int count) {
850 io_glue_commit_types(ig);
852 mm_log((1, "i_writetiff_multi_wiol(ig 0x%p, imgs 0x%p, count %d)\n",
855 /* FIXME: Enable the mmap interface */
857 tif = TIFFClientOpen("No name",
860 (TIFFReadWriteProc) ig->readcb,
861 (TIFFReadWriteProc) ig->writecb,
862 (TIFFSeekProc) comp_seek,
863 (TIFFCloseProc) ig->closecb,
864 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
865 (TIFFMapFileProc) comp_mmap,
866 (TIFFUnmapFileProc) comp_munmap);
871 mm_log((1, "i_writetiff_mulit_wiol: Unable to open tif file for writing\n"));
875 for (i = 0; i < count; ++i) {
876 if (!i_writetiff_low(tif, imgs[i])) {
881 if (!TIFFWriteDirectory(tif)) {
882 i_push_error(0, "Cannot write TIFF directory");
888 (void) TIFFClose(tif);
893 =item i_writetiff_multi_wiol_faxable(ig, imgs, count, fine_mode)
895 Stores an image in the iolayer object.
897 ig - io_object that defines source to write to
898 imgs,count - the images to write
899 fine_mode - select fine or normal mode fax images
906 i_writetiff_multi_wiol_faxable(io_glue *ig, i_img **imgs, int count, int fine) {
910 io_glue_commit_types(ig);
912 mm_log((1, "i_writetiff_multi_wiol(ig 0x%p, imgs 0x%p, count %d)\n",
915 /* FIXME: Enable the mmap interface */
917 tif = TIFFClientOpen("No name",
920 (TIFFReadWriteProc) ig->readcb,
921 (TIFFReadWriteProc) ig->writecb,
922 (TIFFSeekProc) comp_seek,
923 (TIFFCloseProc) ig->closecb,
924 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
925 (TIFFMapFileProc) comp_mmap,
926 (TIFFUnmapFileProc) comp_munmap);
931 mm_log((1, "i_writetiff_mulit_wiol: Unable to open tif file for writing\n"));
935 for (i = 0; i < count; ++i) {
936 if (!i_writetiff_low_faxable(tif, imgs[i], fine)) {
941 if (!TIFFWriteDirectory(tif)) {
942 i_push_error(0, "Cannot write TIFF directory");
948 (void) TIFFClose(tif);
953 =item i_writetiff_wiol(im, ig)
955 Stores an image in the iolayer object.
957 im - image object to write out
958 ig - io_object that defines source to write to
963 i_writetiff_wiol(i_img *img, io_glue *ig) {
967 io_glue_commit_types(ig);
969 mm_log((1, "i_writetiff_wiol(img %p, ig 0x%p)\n", img, ig));
971 /* FIXME: Enable the mmap interface */
973 tif = TIFFClientOpen("No name",
976 (TIFFReadWriteProc) ig->readcb,
977 (TIFFReadWriteProc) ig->writecb,
978 (TIFFSeekProc) comp_seek,
979 (TIFFCloseProc) ig->closecb,
980 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
981 (TIFFMapFileProc) comp_mmap,
982 (TIFFUnmapFileProc) comp_munmap);
987 mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
991 if (!i_writetiff_low(tif, img)) {
996 (void) TIFFClose(tif);
1003 =item i_writetiff_wiol_faxable(i_img *, io_glue *)
1005 Stores an image in the iolayer object in faxable tiff format.
1007 im - image object to write out
1008 ig - io_object that defines source to write to
1010 Note, this may be rewritten to use to simply be a call to a
1011 lower-level function that gives more options for writing tiff at some
1018 i_writetiff_wiol_faxable(i_img *im, io_glue *ig, int fine) {
1022 io_glue_commit_types(ig);
1024 mm_log((1, "i_writetiff_wiol(img %p, ig 0x%p)\n", im, ig));
1026 /* FIXME: Enable the mmap interface */
1028 tif = TIFFClientOpen("No name",
1031 (TIFFReadWriteProc) ig->readcb,
1032 (TIFFReadWriteProc) ig->writecb,
1033 (TIFFSeekProc) comp_seek,
1034 (TIFFCloseProc) ig->closecb,
1035 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
1036 (TIFFMapFileProc) comp_mmap,
1037 (TIFFUnmapFileProc) comp_munmap);
1042 mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
1046 if (!i_writetiff_low_faxable(tif, im, fine)) {
1051 (void) TIFFClose(tif);
1055 static int save_tiff_tags(TIFF *tif, i_img *im) {
1058 for (i = 0; i < text_tag_count; ++i) {
1060 if (i_tags_find(&im->tags, text_tag_names[i].name, 0, &entry)) {
1061 if (!TIFFSetField(tif, text_tag_names[i].tag,
1062 im->tags.tags[entry].data)) {
1063 i_push_errorf(0, "cannot save %s to TIFF", text_tag_names[i].name);
1074 =item expand_4bit_hl(buf, count)
1076 Expands 4-bit/entry packed data into 1 byte/entry.
1078 buf must contain count bytes to be expanded and have 2*count bytes total
1081 The data is expanded in place.
1086 static void expand_4bit_hl(unsigned char *buf, int count) {
1087 while (--count >= 0) {
1088 buf[count*2+1] = buf[count] & 0xF;
1089 buf[count*2] = buf[count] >> 4;
1093 static void pack_4bit_hl(unsigned char *buf, int count) {
1096 buf[i/2] = (buf[i] << 4) + buf[i+1];
1106 Arnar M. Hrafnkelsson <addi@umich.edu>