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 int save_tiff_tags(TIFF *tif, i_img *im);
66 static void expand_4bit_hl(unsigned char *buf, int count);
68 static void pack_4bit_hl(unsigned char *buf, int count);
71 static toff_t sizeproc(thandle_t x) {
77 =item comp_seek(h, o, w)
79 Compatability for 64 bit systems like latest freebsd (internal)
81 h - tiff handle, cast an io_glue object
90 comp_seek(thandle_t h, toff_t o, int w) {
91 io_glue *ig = (io_glue*)h;
92 return (toff_t) ig->seekcb(ig, o, w);
95 static i_img *read_one_tiff(TIFF *tif) {
99 uint32* raster = NULL;
103 int gotXres, gotYres;
105 uint16 bits_per_sample;
111 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
112 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
113 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &channels);
114 tiled = TIFFIsTiled(tif);
115 TIFFGetFieldDefaulted(tif, TIFFTAG_PHOTOMETRIC, &photometric);
116 TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
118 mm_log((1, "i_readtiff_wiol: width=%d, height=%d, channels=%d\n", width, height, channels));
119 mm_log((1, "i_readtiff_wiol: %stiled\n", tiled?"":"not "));
120 mm_log((1, "i_readtiff_wiol: %sbyte swapped\n", TIFFIsByteSwapped(tif)?"":"not "));
122 if (photometric == PHOTOMETRIC_PALETTE && bits_per_sample <= 8) {
124 im = i_img_pal_new(width, height, channels, 256);
127 im = i_img_empty_ch(NULL, width, height, channels);
130 /* resolution tags */
131 TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
132 gotXres = TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres);
133 gotYres = TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres);
134 if (gotXres || gotYres) {
139 if (resunit == RESUNIT_CENTIMETER) {
140 /* from dots per cm to dpi */
144 i_tags_addn(&im->tags, "tiff_resolutionunit", 0, resunit);
145 if (resunit == RESUNIT_NONE)
146 i_tags_addn(&im->tags, "i_aspect_only", 0, 1);
147 i_tags_set_float(&im->tags, "i_xres", 0, xres);
148 i_tags_set_float(&im->tags, "i_yres", 0, yres);
152 for (i = 0; i < text_tag_count; ++i) {
154 if (TIFFGetField(tif, text_tag_names[i].tag, &data)) {
155 mm_log((1, "i_readtiff_wiol: tag %d has value %s\n",
156 text_tag_names[i].tag, data));
157 i_tags_add(&im->tags, text_tag_names[i].name, 0, data,
162 /* TIFFPrintDirectory(tif, stdout, 0); good for debugging */
164 if (photometric == PHOTOMETRIC_PALETTE &&
165 (bits_per_sample == 4 || bits_per_sample == 8)) {
170 unsigned char *buffer;
172 if (!TIFFGetField(tif, TIFFTAG_COLORMAP, maps+0, maps+1, maps+2)) {
173 i_push_error(0, "Cannot get colormap for paletted image");
177 buffer = (unsigned char *)_TIFFmalloc(width+2);
179 i_push_error(0, "out of memory");
184 memset(used, 0, sizeof(used));
185 while (row < height && TIFFReadScanline(tif, buffer, row, 0) > 0) {
186 if (bits_per_sample == 4)
187 expand_4bit_hl(buffer, (width+1)/2);
188 for (col = 0; col < width; ++col) {
189 used[buffer[col]] = 1;
191 i_ppal(im, 0, width, row, buffer);
197 /* Ideally we'd optimize the palette, but that could be expensive
198 since we'd have to re-index every pixel.
200 Optimizing the palette (even at this level) might not
201 be what the user wants, so I don't do it.
203 We'll add a function to optimize a paletted image instead.
205 maxused = (1 << bits_per_sample)-1;
207 while (maxused >= 0 && !used[maxused])
210 for (i = 0; i < 1 << bits_per_sample; ++i) {
212 for (ch = 0; ch < 3; ++ch) {
213 c.channel[ch] = Sample16To8(maps[ch][i]);
215 i_addcolors(im, &c, 1);
223 uint32 tile_width, tile_height;
225 TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width);
226 TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height);
227 mm_log((1, "i_readtiff_wiol: tile_width=%d, tile_height=%d\n", tile_width, tile_height));
229 raster = (uint32*)_TIFFmalloc(tile_width * tile_height * sizeof (uint32));
232 i_push_error(0, "No space for raster buffer");
236 for( row = 0; row < height; row += tile_height ) {
237 for( col = 0; ok && col < width; col += tile_width ) {
238 uint32 i_row, x, newrows, newcols;
240 /* Read the tile into an RGBA array */
241 if (!TIFFReadRGBATile(tif, col, row, raster)) {
245 newrows = (row+tile_height > height) ? height-row : tile_height;
246 mm_log((1, "i_readtiff_wiol: newrows=%d\n", newrows));
247 newcols = (col+tile_width > width ) ? width-row : tile_width;
248 for( i_row = 0; i_row < tile_height; i_row++ ) {
249 for(x = 0; x < newcols; x++) {
251 uint32 temp = raster[x+tile_width*(tile_height-i_row-1)];
252 val.rgba.r = TIFFGetR(temp);
253 val.rgba.g = TIFFGetG(temp);
254 val.rgba.b = TIFFGetB(temp);
255 val.rgba.a = TIFFGetA(temp);
256 i_ppix(im, col+x, row+i_row, &val);
262 uint32 rowsperstrip, row;
263 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
264 mm_log((1, "i_readtiff_wiol: rowsperstrip=%d\n", rowsperstrip));
266 raster = (uint32*)_TIFFmalloc(width * rowsperstrip * sizeof (uint32));
269 i_push_error(0, "No space for raster buffer");
273 for( row = 0; row < height; row += rowsperstrip ) {
274 uint32 newrows, i_row;
276 if (!TIFFReadRGBAStrip(tif, row, raster)) {
281 newrows = (row+rowsperstrip > height) ? height-row : rowsperstrip;
282 mm_log((1, "newrows=%d\n", newrows));
284 for( i_row = 0; i_row < newrows; i_row++ ) {
286 for(x = 0; x<width; x++) {
288 uint32 temp = raster[x+width*(newrows-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, x, i_row+row, &val);
300 mm_log((1, "i_readtiff_wiol: error during reading\n"));
301 i_tags_addn(&im->tags, "i_incomplete", 0, 1);
310 =item i_readtiff_wiol(im, ig)
315 i_readtiff_wiol(io_glue *ig, int length) {
317 TIFFErrorHandler old_handler;
321 old_handler = TIFFSetErrorHandler(error_handler);
323 /* Add code to get the filename info from the iolayer */
324 /* Also add code to check for mmapped code */
326 io_glue_commit_types(ig);
327 mm_log((1, "i_readtiff_wiol(ig %p, length %d)\n", ig, length));
329 tif = TIFFClientOpen("(Iolayer)",
332 (TIFFReadWriteProc) ig->readcb,
333 (TIFFReadWriteProc) ig->writecb,
334 (TIFFSeekProc) comp_seek,
335 (TIFFCloseProc) ig->closecb,
336 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
337 (TIFFMapFileProc) NULL,
338 (TIFFUnmapFileProc) NULL);
341 mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
342 i_push_error(0, "opening file");
343 TIFFSetErrorHandler(old_handler);
347 im = read_one_tiff(tif);
349 if (TIFFLastDirectory(tif)) mm_log((1, "Last directory of tiff file\n"));
350 TIFFSetErrorHandler(old_handler);
356 =item i_readtiff_multi_wiol(ig, length, *count)
358 Reads multiple images from a TIFF.
363 i_readtiff_multi_wiol(io_glue *ig, int length, int *count) {
365 TIFFErrorHandler old_handler;
366 i_img **results = NULL;
367 int result_alloc = 0;
371 old_handler = TIFFSetErrorHandler(error_handler);
373 /* Add code to get the filename info from the iolayer */
374 /* Also add code to check for mmapped code */
376 io_glue_commit_types(ig);
377 mm_log((1, "i_readtiff_wiol(ig %p, length %d)\n", ig, length));
379 tif = TIFFClientOpen("(Iolayer)",
382 (TIFFReadWriteProc) ig->readcb,
383 (TIFFReadWriteProc) ig->writecb,
384 (TIFFSeekProc) comp_seek,
385 (TIFFCloseProc) ig->closecb,
386 (TIFFSizeProc) ig->sizecb,
387 (TIFFMapFileProc) NULL,
388 (TIFFUnmapFileProc) NULL);
391 mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
392 i_push_error(0, "opening file");
393 TIFFSetErrorHandler(old_handler);
399 i_img *im = read_one_tiff(tif);
402 if (++*count > result_alloc) {
403 if (result_alloc == 0) {
405 results = mymalloc(result_alloc * sizeof(i_img *));
410 newresults = myrealloc(results, result_alloc * sizeof(i_img *));
413 results[*count-1] = im;
414 } while (TIFFSetDirectory(tif, ++dirnum));
416 TIFFSetErrorHandler(old_handler);
422 i_writetiff_low_faxable(TIFF *tif, i_img *im, int fine) {
423 uint32 width, height;
424 unsigned char *linebuf = NULL;
430 float vres = fine ? 196 : 98;
436 switch (im->channels) {
446 /* This means a colorspace we don't handle yet */
447 mm_log((1, "i_writetiff_wiol_faxable: don't handle %d channel images.\n", im->channels));
451 /* Add code to get the filename info from the iolayer */
452 /* Also add code to check for mmapped code */
455 mm_log((1, "i_writetiff_wiol_faxable: width=%d, height=%d, channels=%d\n", width, height, im->channels));
457 if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width) )
458 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField width=%d failed\n", width)); return 0; }
459 if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height) )
460 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField length=%d failed\n", height)); return 0; }
461 if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1))
462 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField samplesperpixel=1 failed\n")); return 0; }
463 if (!TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT))
464 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Orientation=topleft\n")); return 0; }
465 if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 1) )
466 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField bitpersample=1\n")); return 0; }
467 if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG))
468 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField planarconfig\n")); return 0; }
469 if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK))
470 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField photometric=%d\n", PHOTOMETRIC_MINISBLACK)); return 0; }
471 if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, 3))
472 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField compression=3\n")); return 0; }
474 linebuf = (unsigned char *)_TIFFmalloc( TIFFScanlineSize(tif) );
476 if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, -1))) {
477 mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField rowsperstrip=-1\n")); return 0; }
479 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
480 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rc);
482 mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField rowsperstrip=%d\n", rowsperstrip));
483 mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField scanlinesize=%d\n", TIFFScanlineSize(tif) ));
484 mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG));
486 if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)204))
487 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Xresolution=204\n")); return 0; }
488 if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, vres))
489 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Yresolution=196\n")); return 0; }
490 if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH)) {
491 mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField ResolutionUnit=%d\n", RESUNIT_INCH)); return 0;
494 if (!save_tiff_tags(tif, im)) {
498 for (y=0; y<height; y++) {
500 for(x=0; x<width; x+=8) {
505 linebuf[linebufpos]=0;
506 bits = width-x; if(bits>8) bits=8;
507 i_gsamp(im, x, x+8, y, luma, &luma_chan, 1);
508 for(bitpos=0;bitpos<bits;bitpos++) {
509 linebuf[linebufpos] |= ((luma[bitpos]>=128)?bitval:0);
514 if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
515 mm_log((1, "i_writetiff_wiol_faxable: TIFFWriteScanline failed.\n"));
519 if (linebuf) _TIFFfree(linebuf);
525 i_writetiff_low(TIFF *tif, i_img *im) {
526 uint32 width, height;
528 uint16 predictor = 0;
530 int jpegcolormode = JPEGCOLORMODE_RGB;
531 uint16 compression = COMPRESSION_PACKBITS;
534 uint32 rowsperstrip = (uint32) -1; /* Let library pick default */
535 unsigned char *linebuf = NULL;
540 int got_xres, got_yres, got_aspectonly, aspect_only, resunit;
542 uint16 bitspersample = 8;
543 uint16 samplesperpixel;
544 uint16 *colors = NULL;
548 channels = im->channels;
552 photometric = PHOTOMETRIC_MINISBLACK;
555 photometric = PHOTOMETRIC_RGB;
556 if (compression == COMPRESSION_JPEG && jpegcolormode == JPEGCOLORMODE_RGB) photometric = PHOTOMETRIC_YCBCR;
557 else if (im->type == i_palette_type) {
558 photometric = PHOTOMETRIC_PALETTE;
562 /* This means a colorspace we don't handle yet */
563 mm_log((1, "i_writetiff_wiol: don't handle %d channel images.\n", channels));
567 /* Add code to get the filename info from the iolayer */
568 /* Also add code to check for mmapped code */
570 /*io_glue_commit_types(ig);*/
571 /*mm_log((1, "i_writetiff_wiol(im 0x%p, ig 0x%p)\n", im, ig));*/
573 mm_log((1, "i_writetiff_low: width=%d, height=%d, channels=%d\n", width, height, channels));
575 if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width) ) {
576 mm_log((1, "i_writetiff_wiol: TIFFSetField width=%d failed\n", width));
579 if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height) ) {
580 mm_log((1, "i_writetiff_wiol: TIFFSetField length=%d failed\n", height));
583 if (!TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT)) {
584 mm_log((1, "i_writetiff_wiol: TIFFSetField Orientation=topleft\n"));
587 if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) {
588 mm_log((1, "i_writetiff_wiol: TIFFSetField planarconfig\n"));
591 if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric)) {
592 mm_log((1, "i_writetiff_wiol: TIFFSetField photometric=%d\n", photometric));
595 if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, compression)) {
596 mm_log((1, "i_writetiff_wiol: TIFFSetField compression=%d\n", compression));
599 samplesperpixel = channels;
600 if (photometric == PHOTOMETRIC_PALETTE) {
603 int count = i_colorcount(im);
613 size = 1 << bitspersample;
614 colors = (uint16 *)_TIFFmalloc(sizeof(uint16) * 3 * size);
616 out[1] = colors + size;
617 out[2] = colors + 2 * size;
619 for (i = 0; i < count; ++i) {
620 i_getcolors(im, i, &c, 1);
621 for (ch = 0; ch < 3; ++ch)
622 out[ch][i] = c.channel[ch] * 257;
624 for (; i < size; ++i) {
625 for (ch = 0; ch < 3; ++ch)
628 if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitspersample)) {
629 mm_log((1, "i_writetiff_wiol: TIFFSetField bitpersample=%d\n",
633 if (!TIFFSetField(tif, TIFFTAG_COLORMAP, out[0], out[1], out[2])) {
634 mm_log((1, "i_writetiff_wiol: TIFFSetField colormap\n"));
639 if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitspersample)) {
640 mm_log((1, "i_writetiff_wiol: TIFFSetField bitpersample=%d\n",
645 if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel)) {
646 mm_log((1, "i_writetiff_wiol: TIFFSetField samplesperpixel=%d failed\n", samplesperpixel));
650 switch (compression) {
651 case COMPRESSION_JPEG:
652 mm_log((1, "i_writetiff_wiol: jpeg compression\n"));
653 if (!TIFFSetField(tif, TIFFTAG_JPEGQUALITY, quality) ) {
654 mm_log((1, "i_writetiff_wiol: TIFFSetField jpegquality=%d\n", quality));
657 if (!TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, jpegcolormode)) {
658 mm_log((1, "i_writetiff_wiol: TIFFSetField jpegcolormode=%d\n", jpegcolormode));
662 case COMPRESSION_LZW:
663 mm_log((1, "i_writetiff_wiol: lzw compression\n"));
665 case COMPRESSION_DEFLATE:
666 mm_log((1, "i_writetiff_wiol: deflate compression\n"));
668 if (!TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor)) {
669 mm_log((1, "i_writetiff_wiol: TIFFSetField predictor=%d\n", predictor));
673 case COMPRESSION_PACKBITS:
674 mm_log((1, "i_writetiff_wiol: packbits compression\n"));
677 mm_log((1, "i_writetiff_wiol: unknown compression %d\n", compression));
681 linebytes = channels * width;
682 linebytes = TIFFScanlineSize(tif) > linebytes ? linebytes
683 : TIFFScanlineSize(tif);
684 /* working space for the scanlines - we go from 8-bit/pixel to 4 */
685 if (photometric == PHOTOMETRIC_PALETTE && bitspersample == 4)
686 linebytes += linebytes + 1;
687 linebuf = (unsigned char *)_TIFFmalloc(linebytes);
689 if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, rowsperstrip))) {
690 mm_log((1, "i_writetiff_wiol: TIFFSetField rowsperstrip=%d\n", rowsperstrip)); return 0; }
692 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
693 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rc);
695 mm_log((1, "i_writetiff_wiol: TIFFGetField rowsperstrip=%d\n", rowsperstrip));
696 mm_log((1, "i_writetiff_wiol: TIFFGetField scanlinesize=%d\n", TIFFScanlineSize(tif) ));
697 mm_log((1, "i_writetiff_wiol: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG));
698 mm_log((1, "i_writetiff_wiol: bitspersample = %d\n", bitspersample));
700 got_xres = i_tags_get_float(&im->tags, "i_xres", 0, &xres);
701 got_yres = i_tags_get_float(&im->tags, "i_yres", 0, &yres);
702 if (!i_tags_get_int(&im->tags, "i_aspect_only", 0,&aspect_only))
704 if (!i_tags_get_int(&im->tags, "tiff_resolutionunit", 0, &resunit))
705 resunit = RESUNIT_INCH;
706 if (got_xres || got_yres) {
712 resunit = RESUNIT_NONE;
715 if (resunit == RESUNIT_CENTIMETER) {
720 resunit = RESUNIT_INCH;
723 if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)xres)) {
724 i_push_error(0, "cannot set TIFFTAG_XRESOLUTION tag");
727 if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)yres)) {
728 i_push_error(0, "cannot set TIFFTAG_YRESOLUTION tag");
731 if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (uint16)resunit)) {
732 i_push_error(0, "cannot set TIFFTAG_RESOLUTIONUNIT tag");
737 if (!save_tiff_tags(tif, im)) {
741 if (photometric == PHOTOMETRIC_PALETTE) {
742 for (y = 0; y < height; ++y) {
743 i_gpal(im, 0, width, y, linebuf);
744 if (bitspersample == 4)
745 pack_4bit_hl(linebuf, width);
746 if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
747 mm_log((1, "i_writetiff_wiol: TIFFWriteScanline failed.\n"));
748 if (linebuf) _TIFFfree(linebuf);
749 if (colors) _TIFFfree(colors);
755 for (y=0; y<height; y++) {
757 for(x=0; x<width; x++) {
758 (void) i_gpix(im, x, y,&val);
759 for(ch=0; ch<channels; ch++)
760 linebuf[ci++] = val.channel[ch];
762 if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
763 mm_log((1, "i_writetiff_wiol: TIFFWriteScanline failed.\n"));
764 if (linebuf) _TIFFfree(linebuf);
765 if (colors) _TIFFfree(colors);
770 if (linebuf) _TIFFfree(linebuf);
771 if (colors) _TIFFfree(colors);
776 =item i_writetiff_multi_wiol(ig, imgs, count, fine_mode)
778 Stores an image in the iolayer object.
780 ig - io_object that defines source to write to
781 imgs,count - the images to write
787 i_writetiff_multi_wiol(io_glue *ig, i_img **imgs, int count) {
791 io_glue_commit_types(ig);
793 mm_log((1, "i_writetiff_multi_wiol(ig 0x%p, imgs 0x%p, count %d)\n",
796 /* FIXME: Enable the mmap interface */
798 tif = TIFFClientOpen("No name",
801 (TIFFReadWriteProc) ig->readcb,
802 (TIFFReadWriteProc) ig->writecb,
803 (TIFFSeekProc) comp_seek,
804 (TIFFCloseProc) ig->closecb,
805 (TIFFSizeProc) ig->sizecb,
806 (TIFFMapFileProc) NULL,
807 (TIFFUnmapFileProc) NULL);
812 mm_log((1, "i_writetiff_mulit_wiol: Unable to open tif file for writing\n"));
816 for (i = 0; i < count; ++i) {
817 if (!i_writetiff_low(tif, imgs[i])) {
822 if (!TIFFWriteDirectory(tif)) {
823 i_push_error(0, "Cannot write TIFF directory");
829 (void) TIFFClose(tif);
834 =item i_writetiff_multi_wiol_faxable(ig, imgs, count, fine_mode)
836 Stores an image in the iolayer object.
838 ig - io_object that defines source to write to
839 imgs,count - the images to write
840 fine_mode - select fine or normal mode fax images
847 i_writetiff_multi_wiol_faxable(io_glue *ig, i_img **imgs, int count, int fine) {
851 io_glue_commit_types(ig);
853 mm_log((1, "i_writetiff_multi_wiol(ig 0x%p, imgs 0x%p, count %d)\n",
856 /* FIXME: Enable the mmap interface */
858 tif = TIFFClientOpen("No name",
861 (TIFFReadWriteProc) ig->readcb,
862 (TIFFReadWriteProc) ig->writecb,
863 (TIFFSeekProc) comp_seek,
864 (TIFFCloseProc) ig->closecb,
865 (TIFFSizeProc) ig->sizecb,
866 (TIFFMapFileProc) NULL,
867 (TIFFUnmapFileProc) NULL);
872 mm_log((1, "i_writetiff_mulit_wiol: Unable to open tif file for writing\n"));
876 for (i = 0; i < count; ++i) {
877 if (!i_writetiff_low_faxable(tif, imgs[i], fine)) {
882 if (!TIFFWriteDirectory(tif)) {
883 i_push_error(0, "Cannot write TIFF directory");
889 (void) TIFFClose(tif);
894 =item i_writetiff_wiol(im, ig)
896 Stores an image in the iolayer object.
898 im - image object to write out
899 ig - io_object that defines source to write to
904 i_writetiff_wiol(i_img *img, io_glue *ig) {
908 io_glue_commit_types(ig);
910 mm_log((1, "i_writetiff_wiol(img %p, ig 0x%p)\n", img, ig));
912 /* FIXME: Enable the mmap interface */
914 tif = TIFFClientOpen("No name",
917 (TIFFReadWriteProc) ig->readcb,
918 (TIFFReadWriteProc) ig->writecb,
919 (TIFFSeekProc) comp_seek,
920 (TIFFCloseProc) ig->closecb,
921 (TIFFSizeProc) ig->sizecb,
922 (TIFFMapFileProc) NULL,
923 (TIFFUnmapFileProc) NULL);
928 mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
932 if (!i_writetiff_low(tif, img)) {
937 (void) TIFFClose(tif);
944 =item i_writetiff_wiol_faxable(i_img *, io_glue *)
946 Stores an image in the iolayer object in faxable tiff format.
948 im - image object to write out
949 ig - io_object that defines source to write to
951 Note, this may be rewritten to use to simply be a call to a
952 lower-level function that gives more options for writing tiff at some
959 i_writetiff_wiol_faxable(i_img *im, io_glue *ig, int fine) {
963 io_glue_commit_types(ig);
965 mm_log((1, "i_writetiff_wiol(img %p, ig 0x%p)\n", im, ig));
967 /* FIXME: Enable the mmap interface */
969 tif = TIFFClientOpen("No name",
972 (TIFFReadWriteProc) ig->readcb,
973 (TIFFReadWriteProc) ig->writecb,
974 (TIFFSeekProc) comp_seek,
975 (TIFFCloseProc) ig->closecb,
976 (TIFFSizeProc) ig->sizecb,
977 (TIFFMapFileProc) NULL,
978 (TIFFUnmapFileProc) NULL);
983 mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
987 if (!i_writetiff_low_faxable(tif, im, fine)) {
992 (void) TIFFClose(tif);
996 static int save_tiff_tags(TIFF *tif, i_img *im) {
999 for (i = 0; i < text_tag_count; ++i) {
1001 if (i_tags_find(&im->tags, text_tag_names[i].name, 0, &entry)) {
1002 if (!TIFFSetField(tif, text_tag_names[i].tag,
1003 im->tags.tags[entry].data)) {
1004 i_push_errorf(0, "cannot save %s to TIFF", text_tag_names[i].name);
1015 =item expand_4bit_hl(buf, count)
1017 Expands 4-bit/entry packed data into 1 byte/entry.
1019 buf must contain count bytes to be expanded and have 2*count bytes total
1022 The data is expanded in place.
1027 static void expand_4bit_hl(unsigned char *buf, int count) {
1028 while (--count >= 0) {
1029 buf[count*2+1] = buf[count] & 0xF;
1030 buf[count*2] = buf[count] >> 4;
1034 static void pack_4bit_hl(unsigned char *buf, int count) {
1037 buf[i/2] = (buf[i] << 4) + buf[i+1];
1047 Arnar M. Hrafnkelsson <addi@umich.edu>