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);
167 /* resolution tags */
168 TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
169 gotXres = TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres);
170 gotYres = TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres);
171 if (gotXres || gotYres) {
176 if (resunit == RESUNIT_CENTIMETER) {
177 /* from dots per cm to dpi */
181 i_tags_addn(&im->tags, "tiff_resolutionunit", 0, resunit);
182 if (resunit == RESUNIT_NONE)
183 i_tags_addn(&im->tags, "i_aspect_only", 0, 1);
184 i_tags_set_float(&im->tags, "i_xres", 0, xres);
185 i_tags_set_float(&im->tags, "i_yres", 0, yres);
189 for (i = 0; i < text_tag_count; ++i) {
191 if (TIFFGetField(tif, text_tag_names[i].tag, &data)) {
192 mm_log((1, "i_readtiff_wiol: tag %d has value %s\n",
193 text_tag_names[i].tag, data));
194 i_tags_add(&im->tags, text_tag_names[i].name, 0, data,
199 /* TIFFPrintDirectory(tif, stdout, 0); good for debugging */
201 if (photometric == PHOTOMETRIC_PALETTE &&
202 (bits_per_sample == 4 || bits_per_sample == 8)) {
207 unsigned char *buffer;
209 if (!TIFFGetField(tif, TIFFTAG_COLORMAP, maps+0, maps+1, maps+2)) {
210 i_push_error(0, "Cannot get colormap for paletted image");
214 buffer = (unsigned char *)_TIFFmalloc(width+2);
216 i_push_error(0, "out of memory");
221 memset(used, 0, sizeof(used));
222 while (row < height && TIFFReadScanline(tif, buffer, row, 0) > 0) {
223 if (bits_per_sample == 4)
224 expand_4bit_hl(buffer, (width+1)/2);
225 for (col = 0; col < width; ++col) {
226 used[buffer[col]] = 1;
228 i_ppal(im, 0, width, row, buffer);
234 /* Ideally we'd optimize the palette, but that could be expensive
235 since we'd have to re-index every pixel.
237 Optimizing the palette (even at this level) might not
238 be what the user wants, so I don't do it.
240 We'll add a function to optimize a paletted image instead.
242 maxused = (1 << bits_per_sample)-1;
244 while (maxused >= 0 && !used[maxused])
247 for (i = 0; i < 1 << bits_per_sample; ++i) {
249 for (ch = 0; ch < 3; ++ch) {
250 c.channel[ch] = Sample16To8(maps[ch][i]);
252 i_addcolors(im, &c, 1);
260 uint32 tile_width, tile_height;
262 TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width);
263 TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height);
264 mm_log((1, "i_readtiff_wiol: tile_width=%d, tile_height=%d\n", tile_width, tile_height));
266 raster = (uint32*)_TIFFmalloc(tile_width * tile_height * sizeof (uint32));
269 i_push_error(0, "No space for raster buffer");
273 for( row = 0; row < height; row += tile_height ) {
274 for( col = 0; ok && col < width; col += tile_width ) {
275 uint32 i_row, x, newrows, newcols;
277 /* Read the tile into an RGBA array */
278 if (!TIFFReadRGBATile(tif, col, row, raster)) {
282 newrows = (row+tile_height > height) ? height-row : tile_height;
283 mm_log((1, "i_readtiff_wiol: newrows=%d\n", newrows));
284 newcols = (col+tile_width > width ) ? width-row : tile_width;
285 for( i_row = 0; i_row < tile_height; i_row++ ) {
286 for(x = 0; x < newcols; x++) {
288 uint32 temp = raster[x+tile_width*(tile_height-i_row-1)];
289 val.rgba.r = TIFFGetR(temp);
290 val.rgba.g = TIFFGetG(temp);
291 val.rgba.b = TIFFGetB(temp);
292 val.rgba.a = TIFFGetA(temp);
293 i_ppix(im, col+x, row+i_row, &val);
299 uint32 rowsperstrip, row;
300 int rc = TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
301 mm_log((1, "i_readtiff_wiol: rowsperstrip=%d rc = %d\n", rowsperstrip, rc));
303 if (rc != 1 || rowsperstrip==-1) {
304 rowsperstrip = height;
307 raster = (uint32*)_TIFFmalloc(width * rowsperstrip * sizeof (uint32));
310 i_push_error(0, "No space for raster buffer");
314 for( row = 0; row < height; row += rowsperstrip ) {
315 uint32 newrows, i_row;
317 if (!TIFFReadRGBAStrip(tif, row, raster)) {
322 newrows = (row+rowsperstrip > height) ? height-row : rowsperstrip;
323 mm_log((1, "newrows=%d\n", newrows));
325 for( i_row = 0; i_row < newrows; i_row++ ) {
327 for(x = 0; x<width; x++) {
329 uint32 temp = raster[x+width*(newrows-i_row-1)];
330 val.rgba.r = TIFFGetR(temp);
331 val.rgba.g = TIFFGetG(temp);
332 val.rgba.b = TIFFGetB(temp);
333 val.rgba.a = TIFFGetA(temp);
334 i_ppix(im, x, i_row+row, &val);
341 mm_log((1, "i_readtiff_wiol: error during reading\n"));
342 i_tags_addn(&im->tags, "i_incomplete", 0, 1);
351 =item i_readtiff_wiol(im, ig)
356 i_readtiff_wiol(io_glue *ig, int length) {
358 TIFFErrorHandler old_handler;
359 TIFFErrorHandler old_warn_handler;
363 old_handler = TIFFSetErrorHandler(error_handler);
364 old_warn_handler = TIFFSetWarningHandler(warn_handler);
366 /* Add code to get the filename info from the iolayer */
367 /* Also add code to check for mmapped code */
369 io_glue_commit_types(ig);
370 mm_log((1, "i_readtiff_wiol(ig %p, length %d)\n", ig, length));
372 tif = TIFFClientOpen("(Iolayer)",
375 (TIFFReadWriteProc) ig->readcb,
376 (TIFFReadWriteProc) ig->writecb,
377 (TIFFSeekProc) comp_seek,
378 (TIFFCloseProc) ig->closecb,
379 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
380 (TIFFMapFileProc) comp_mmap,
381 (TIFFUnmapFileProc) comp_munmap);
384 mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
385 i_push_error(0, "opening file");
386 TIFFSetErrorHandler(old_handler);
387 TIFFSetWarningHandler(old_warn_handler);
391 im = read_one_tiff(tif);
393 if (TIFFLastDirectory(tif)) mm_log((1, "Last directory of tiff file\n"));
394 TIFFSetErrorHandler(old_handler);
395 TIFFSetWarningHandler(old_warn_handler);
401 =item i_readtiff_multi_wiol(ig, length, *count)
403 Reads multiple images from a TIFF.
408 i_readtiff_multi_wiol(io_glue *ig, int length, int *count) {
410 TIFFErrorHandler old_handler;
411 TIFFErrorHandler old_warn_handler;
412 i_img **results = NULL;
413 int result_alloc = 0;
417 old_handler = TIFFSetErrorHandler(error_handler);
418 old_warn_handler = TIFFSetWarningHandler(warn_handler);
420 /* Add code to get the filename info from the iolayer */
421 /* Also add code to check for mmapped code */
423 io_glue_commit_types(ig);
424 mm_log((1, "i_readtiff_wiol(ig %p, length %d)\n", ig, length));
426 tif = TIFFClientOpen("(Iolayer)",
429 (TIFFReadWriteProc) ig->readcb,
430 (TIFFReadWriteProc) ig->writecb,
431 (TIFFSeekProc) comp_seek,
432 (TIFFCloseProc) ig->closecb,
433 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
434 (TIFFMapFileProc) comp_mmap,
435 (TIFFUnmapFileProc) comp_munmap);
438 mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
439 i_push_error(0, "opening file");
440 TIFFSetErrorHandler(old_handler);
441 TIFFSetWarningHandler(old_warn_handler);
447 i_img *im = read_one_tiff(tif);
450 if (++*count > result_alloc) {
451 if (result_alloc == 0) {
453 results = mymalloc(result_alloc * sizeof(i_img *));
458 newresults = myrealloc(results, result_alloc * sizeof(i_img *));
460 i_img_destroy(im); /* don't leak it */
463 results = newresults;
466 results[*count-1] = im;
467 } while (TIFFSetDirectory(tif, ++dirnum));
469 TIFFSetWarningHandler(old_warn_handler);
470 TIFFSetErrorHandler(old_handler);
476 i_writetiff_low_faxable(TIFF *tif, i_img *im, int fine) {
477 uint32 width, height;
478 unsigned char *linebuf = NULL;
484 float vres = fine ? 196 : 98;
490 switch (im->channels) {
500 /* This means a colorspace we don't handle yet */
501 mm_log((1, "i_writetiff_wiol_faxable: don't handle %d channel images.\n", im->channels));
505 /* Add code to get the filename info from the iolayer */
506 /* Also add code to check for mmapped code */
509 mm_log((1, "i_writetiff_wiol_faxable: width=%d, height=%d, channels=%d\n", width, height, im->channels));
511 if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width) )
512 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField width=%d failed\n", width)); return 0; }
513 if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height) )
514 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField length=%d failed\n", height)); return 0; }
515 if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1))
516 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField samplesperpixel=1 failed\n")); return 0; }
517 if (!TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT))
518 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Orientation=topleft\n")); return 0; }
519 if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 1) )
520 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField bitpersample=1\n")); return 0; }
521 if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG))
522 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField planarconfig\n")); return 0; }
523 if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK))
524 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField photometric=%d\n", PHOTOMETRIC_MINISBLACK)); return 0; }
525 if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, 3))
526 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField compression=3\n")); return 0; }
528 linebuf = (unsigned char *)_TIFFmalloc( TIFFScanlineSize(tif) );
530 if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, -1))) {
531 mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField rowsperstrip=-1\n")); return 0; }
533 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
534 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rc);
536 mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField rowsperstrip=%d\n", rowsperstrip));
537 mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField scanlinesize=%d\n", TIFFScanlineSize(tif) ));
538 mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG));
540 if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)204))
541 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Xresolution=204\n")); return 0; }
542 if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, vres))
543 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Yresolution=196\n")); return 0; }
544 if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH)) {
545 mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField ResolutionUnit=%d\n", RESUNIT_INCH)); return 0;
548 if (!save_tiff_tags(tif, im)) {
552 for (y=0; y<height; y++) {
554 for(x=0; x<width; x+=8) {
559 linebuf[linebufpos]=0;
560 bits = width-x; if(bits>8) bits=8;
561 i_gsamp(im, x, x+8, y, luma, &luma_chan, 1);
562 for(bitpos=0;bitpos<bits;bitpos++) {
563 linebuf[linebufpos] |= ((luma[bitpos]>=128)?bitval:0);
568 if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
569 mm_log((1, "i_writetiff_wiol_faxable: TIFFWriteScanline failed.\n"));
573 if (linebuf) _TIFFfree(linebuf);
579 i_writetiff_low(TIFF *tif, i_img *im) {
580 uint32 width, height;
582 uint16 predictor = 0;
584 int jpegcolormode = JPEGCOLORMODE_RGB;
585 uint16 compression = COMPRESSION_PACKBITS;
588 uint32 rowsperstrip = (uint32) -1; /* Let library pick default */
589 unsigned char *linebuf = NULL;
594 int got_xres, got_yres, got_aspectonly, aspect_only, resunit;
596 uint16 bitspersample = 8;
597 uint16 samplesperpixel;
598 uint16 *colors = NULL;
602 channels = im->channels;
606 photometric = PHOTOMETRIC_MINISBLACK;
609 photometric = PHOTOMETRIC_RGB;
610 if (compression == COMPRESSION_JPEG && jpegcolormode == JPEGCOLORMODE_RGB) photometric = PHOTOMETRIC_YCBCR;
611 else if (im->type == i_palette_type) {
612 photometric = PHOTOMETRIC_PALETTE;
616 /* This means a colorspace we don't handle yet */
617 mm_log((1, "i_writetiff_wiol: don't handle %d channel images.\n", channels));
621 /* Add code to get the filename info from the iolayer */
622 /* Also add code to check for mmapped code */
624 /*io_glue_commit_types(ig);*/
625 /*mm_log((1, "i_writetiff_wiol(im 0x%p, ig 0x%p)\n", im, ig));*/
627 mm_log((1, "i_writetiff_low: width=%d, height=%d, channels=%d\n", width, height, channels));
629 if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width) ) {
630 mm_log((1, "i_writetiff_wiol: TIFFSetField width=%d failed\n", width));
633 if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height) ) {
634 mm_log((1, "i_writetiff_wiol: TIFFSetField length=%d failed\n", height));
637 if (!TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT)) {
638 mm_log((1, "i_writetiff_wiol: TIFFSetField Orientation=topleft\n"));
641 if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) {
642 mm_log((1, "i_writetiff_wiol: TIFFSetField planarconfig\n"));
645 if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric)) {
646 mm_log((1, "i_writetiff_wiol: TIFFSetField photometric=%d\n", photometric));
649 if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, compression)) {
650 mm_log((1, "i_writetiff_wiol: TIFFSetField compression=%d\n", compression));
653 samplesperpixel = channels;
654 if (photometric == PHOTOMETRIC_PALETTE) {
657 int count = i_colorcount(im);
667 size = 1 << bitspersample;
668 colors = (uint16 *)_TIFFmalloc(sizeof(uint16) * 3 * size);
670 out[1] = colors + size;
671 out[2] = colors + 2 * size;
673 for (i = 0; i < count; ++i) {
674 i_getcolors(im, i, &c, 1);
675 for (ch = 0; ch < 3; ++ch)
676 out[ch][i] = c.channel[ch] * 257;
678 for (; i < size; ++i) {
679 for (ch = 0; ch < 3; ++ch)
682 if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitspersample)) {
683 mm_log((1, "i_writetiff_wiol: TIFFSetField bitpersample=%d\n",
687 if (!TIFFSetField(tif, TIFFTAG_COLORMAP, out[0], out[1], out[2])) {
688 mm_log((1, "i_writetiff_wiol: TIFFSetField colormap\n"));
693 if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitspersample)) {
694 mm_log((1, "i_writetiff_wiol: TIFFSetField bitpersample=%d\n",
699 if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel)) {
700 mm_log((1, "i_writetiff_wiol: TIFFSetField samplesperpixel=%d failed\n", samplesperpixel));
704 switch (compression) {
705 case COMPRESSION_JPEG:
706 mm_log((1, "i_writetiff_wiol: jpeg compression\n"));
707 if (!TIFFSetField(tif, TIFFTAG_JPEGQUALITY, quality) ) {
708 mm_log((1, "i_writetiff_wiol: TIFFSetField jpegquality=%d\n", quality));
711 if (!TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, jpegcolormode)) {
712 mm_log((1, "i_writetiff_wiol: TIFFSetField jpegcolormode=%d\n", jpegcolormode));
716 case COMPRESSION_LZW:
717 mm_log((1, "i_writetiff_wiol: lzw compression\n"));
719 case COMPRESSION_DEFLATE:
720 mm_log((1, "i_writetiff_wiol: deflate compression\n"));
722 if (!TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor)) {
723 mm_log((1, "i_writetiff_wiol: TIFFSetField predictor=%d\n", predictor));
727 case COMPRESSION_PACKBITS:
728 mm_log((1, "i_writetiff_wiol: packbits compression\n"));
731 mm_log((1, "i_writetiff_wiol: unknown compression %d\n", compression));
735 linebytes = channels * width;
736 linebytes = TIFFScanlineSize(tif) > linebytes ? linebytes
737 : TIFFScanlineSize(tif);
738 /* working space for the scanlines - we go from 8-bit/pixel to 4 */
739 if (photometric == PHOTOMETRIC_PALETTE && bitspersample == 4)
740 linebytes += linebytes + 1;
741 linebuf = (unsigned char *)_TIFFmalloc(linebytes);
743 if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, rowsperstrip))) {
744 mm_log((1, "i_writetiff_wiol: TIFFSetField rowsperstrip=%d\n", rowsperstrip)); return 0; }
746 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
747 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rc);
749 mm_log((1, "i_writetiff_wiol: TIFFGetField rowsperstrip=%d\n", rowsperstrip));
750 mm_log((1, "i_writetiff_wiol: TIFFGetField scanlinesize=%d\n", TIFFScanlineSize(tif) ));
751 mm_log((1, "i_writetiff_wiol: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG));
752 mm_log((1, "i_writetiff_wiol: bitspersample = %d\n", bitspersample));
754 got_xres = i_tags_get_float(&im->tags, "i_xres", 0, &xres);
755 got_yres = i_tags_get_float(&im->tags, "i_yres", 0, &yres);
756 if (!i_tags_get_int(&im->tags, "i_aspect_only", 0,&aspect_only))
758 if (!i_tags_get_int(&im->tags, "tiff_resolutionunit", 0, &resunit))
759 resunit = RESUNIT_INCH;
760 if (got_xres || got_yres) {
766 resunit = RESUNIT_NONE;
769 if (resunit == RESUNIT_CENTIMETER) {
774 resunit = RESUNIT_INCH;
777 if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)xres)) {
778 i_push_error(0, "cannot set TIFFTAG_XRESOLUTION tag");
781 if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)yres)) {
782 i_push_error(0, "cannot set TIFFTAG_YRESOLUTION tag");
785 if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (uint16)resunit)) {
786 i_push_error(0, "cannot set TIFFTAG_RESOLUTIONUNIT tag");
791 if (!save_tiff_tags(tif, im)) {
795 if (photometric == PHOTOMETRIC_PALETTE) {
796 for (y = 0; y < height; ++y) {
797 i_gpal(im, 0, width, y, linebuf);
798 if (bitspersample == 4)
799 pack_4bit_hl(linebuf, width);
800 if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
801 mm_log((1, "i_writetiff_wiol: TIFFWriteScanline failed.\n"));
802 if (linebuf) _TIFFfree(linebuf);
803 if (colors) _TIFFfree(colors);
809 for (y=0; y<height; y++) {
811 for(x=0; x<width; x++) {
812 (void) i_gpix(im, x, y,&val);
813 for(ch=0; ch<channels; ch++)
814 linebuf[ci++] = val.channel[ch];
816 if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
817 mm_log((1, "i_writetiff_wiol: TIFFWriteScanline failed.\n"));
818 if (linebuf) _TIFFfree(linebuf);
819 if (colors) _TIFFfree(colors);
824 if (linebuf) _TIFFfree(linebuf);
825 if (colors) _TIFFfree(colors);
830 =item i_writetiff_multi_wiol(ig, imgs, count, fine_mode)
832 Stores an image in the iolayer object.
834 ig - io_object that defines source to write to
835 imgs,count - the images to write
841 i_writetiff_multi_wiol(io_glue *ig, i_img **imgs, int count) {
845 io_glue_commit_types(ig);
847 mm_log((1, "i_writetiff_multi_wiol(ig 0x%p, imgs 0x%p, count %d)\n",
850 /* FIXME: Enable the mmap interface */
852 tif = TIFFClientOpen("No name",
855 (TIFFReadWriteProc) ig->readcb,
856 (TIFFReadWriteProc) ig->writecb,
857 (TIFFSeekProc) comp_seek,
858 (TIFFCloseProc) ig->closecb,
859 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
860 (TIFFMapFileProc) comp_mmap,
861 (TIFFUnmapFileProc) comp_munmap);
866 mm_log((1, "i_writetiff_mulit_wiol: Unable to open tif file for writing\n"));
870 for (i = 0; i < count; ++i) {
871 if (!i_writetiff_low(tif, imgs[i])) {
876 if (!TIFFWriteDirectory(tif)) {
877 i_push_error(0, "Cannot write TIFF directory");
883 (void) TIFFClose(tif);
888 =item i_writetiff_multi_wiol_faxable(ig, imgs, count, fine_mode)
890 Stores an image in the iolayer object.
892 ig - io_object that defines source to write to
893 imgs,count - the images to write
894 fine_mode - select fine or normal mode fax images
901 i_writetiff_multi_wiol_faxable(io_glue *ig, i_img **imgs, int count, int fine) {
905 io_glue_commit_types(ig);
907 mm_log((1, "i_writetiff_multi_wiol(ig 0x%p, imgs 0x%p, count %d)\n",
910 /* FIXME: Enable the mmap interface */
912 tif = TIFFClientOpen("No name",
915 (TIFFReadWriteProc) ig->readcb,
916 (TIFFReadWriteProc) ig->writecb,
917 (TIFFSeekProc) comp_seek,
918 (TIFFCloseProc) ig->closecb,
919 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
920 (TIFFMapFileProc) comp_mmap,
921 (TIFFUnmapFileProc) comp_munmap);
926 mm_log((1, "i_writetiff_mulit_wiol: Unable to open tif file for writing\n"));
930 for (i = 0; i < count; ++i) {
931 if (!i_writetiff_low_faxable(tif, imgs[i], fine)) {
936 if (!TIFFWriteDirectory(tif)) {
937 i_push_error(0, "Cannot write TIFF directory");
943 (void) TIFFClose(tif);
948 =item i_writetiff_wiol(im, ig)
950 Stores an image in the iolayer object.
952 im - image object to write out
953 ig - io_object that defines source to write to
958 i_writetiff_wiol(i_img *img, io_glue *ig) {
962 io_glue_commit_types(ig);
964 mm_log((1, "i_writetiff_wiol(img %p, ig 0x%p)\n", img, ig));
966 /* FIXME: Enable the mmap interface */
968 tif = TIFFClientOpen("No name",
971 (TIFFReadWriteProc) ig->readcb,
972 (TIFFReadWriteProc) ig->writecb,
973 (TIFFSeekProc) comp_seek,
974 (TIFFCloseProc) ig->closecb,
975 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
976 (TIFFMapFileProc) comp_mmap,
977 (TIFFUnmapFileProc) comp_munmap);
982 mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
986 if (!i_writetiff_low(tif, img)) {
991 (void) TIFFClose(tif);
998 =item i_writetiff_wiol_faxable(i_img *, io_glue *)
1000 Stores an image in the iolayer object in faxable tiff format.
1002 im - image object to write out
1003 ig - io_object that defines source to write to
1005 Note, this may be rewritten to use to simply be a call to a
1006 lower-level function that gives more options for writing tiff at some
1013 i_writetiff_wiol_faxable(i_img *im, io_glue *ig, int fine) {
1017 io_glue_commit_types(ig);
1019 mm_log((1, "i_writetiff_wiol(img %p, ig 0x%p)\n", im, ig));
1021 /* FIXME: Enable the mmap interface */
1023 tif = TIFFClientOpen("No name",
1026 (TIFFReadWriteProc) ig->readcb,
1027 (TIFFReadWriteProc) ig->writecb,
1028 (TIFFSeekProc) comp_seek,
1029 (TIFFCloseProc) ig->closecb,
1030 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
1031 (TIFFMapFileProc) comp_mmap,
1032 (TIFFUnmapFileProc) comp_munmap);
1037 mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
1041 if (!i_writetiff_low_faxable(tif, im, fine)) {
1046 (void) TIFFClose(tif);
1050 static int save_tiff_tags(TIFF *tif, i_img *im) {
1053 for (i = 0; i < text_tag_count; ++i) {
1055 if (i_tags_find(&im->tags, text_tag_names[i].name, 0, &entry)) {
1056 if (!TIFFSetField(tif, text_tag_names[i].tag,
1057 im->tags.tags[entry].data)) {
1058 i_push_errorf(0, "cannot save %s to TIFF", text_tag_names[i].name);
1069 =item expand_4bit_hl(buf, count)
1071 Expands 4-bit/entry packed data into 1 byte/entry.
1073 buf must contain count bytes to be expanded and have 2*count bytes total
1076 The data is expanded in place.
1081 static void expand_4bit_hl(unsigned char *buf, int count) {
1082 while (--count >= 0) {
1083 buf[count*2+1] = buf[count] & 0xF;
1084 buf[count*2] = buf[count] >> 4;
1088 static void pack_4bit_hl(unsigned char *buf, int count) {
1091 buf[i/2] = (buf[i] << 4) + buf[i+1];
1101 Arnar M. Hrafnkelsson <addi@umich.edu>