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 #define WARN_BUFFER_LIMIT 10000
65 static char *warn_buffer = NULL;
66 static int warn_buffer_size = 0;
68 static void warn_handler(char const *module, char const *fmt, va_list ap) {
73 vsnprintf(buf, sizeof(buf), fmt, ap);
75 vsprintf(buf, fmt, ap);
77 if (!warn_buffer || strlen(warn_buffer)+strlen(buf)+2 > warn_buffer_size) {
78 int new_size = warn_buffer_size + strlen(buf) + 2;
79 char *old_buffer = warn_buffer;
80 if (new_size > WARN_BUFFER_LIMIT) {
81 new_size = WARN_BUFFER_LIMIT;
83 warn_buffer = myrealloc(warn_buffer, new_size);
84 if (!old_buffer) *warn_buffer = '\0';
85 warn_buffer_size = new_size;
87 if (strlen(warn_buffer)+strlen(buf)+2 <= warn_buffer_size) {
88 strcat(warn_buffer, buf);
89 strcat(warn_buffer, "\n");
93 static int save_tiff_tags(TIFF *tif, i_img *im);
95 static void expand_4bit_hl(unsigned char *buf, int count);
97 static void pack_4bit_hl(unsigned char *buf, int count);
100 static toff_t sizeproc(thandle_t x) {
106 =item comp_seek(h, o, w)
108 Compatability for 64 bit systems like latest freebsd (internal)
110 h - tiff handle, cast an io_glue object
119 comp_seek(thandle_t h, toff_t o, int w) {
120 io_glue *ig = (io_glue*)h;
121 return (toff_t) ig->seekcb(ig, o, w);
125 =item comp_mmap(thandle_t, tdata_t*, toff_t*)
129 This shouldn't ever be called but newer tifflibs want it anyway.
136 comp_mmap(thandle_t h, tdata_t*p, toff_t*off) {
141 =item comp_munmap(thandle_t h, tdata_t p, toff_t off)
145 This shouldn't ever be called but newer tifflibs want it anyway.
151 comp_munmap(thandle_t h, tdata_t p, toff_t off) {
155 static i_img *read_one_tiff(TIFF *tif) {
157 uint32 width, height;
159 uint32* raster = NULL;
163 int gotXres, gotYres;
165 uint16 bits_per_sample;
171 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
172 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
173 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &channels);
174 tiled = TIFFIsTiled(tif);
175 TIFFGetFieldDefaulted(tif, TIFFTAG_PHOTOMETRIC, &photometric);
176 TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
178 mm_log((1, "i_readtiff_wiol: width=%d, height=%d, channels=%d\n", width, height, channels));
179 mm_log((1, "i_readtiff_wiol: %stiled\n", tiled?"":"not "));
180 mm_log((1, "i_readtiff_wiol: %sbyte swapped\n", TIFFIsByteSwapped(tif)?"":"not "));
182 if (photometric == PHOTOMETRIC_PALETTE && bits_per_sample <= 8) {
184 im = i_img_pal_new(width, height, channels, 256);
187 im = i_img_empty_ch(NULL, width, height, channels);
193 /* resolution tags */
194 TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
195 gotXres = TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres);
196 gotYres = TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres);
197 if (gotXres || gotYres) {
202 if (resunit == RESUNIT_CENTIMETER) {
203 /* from dots per cm to dpi */
207 i_tags_addn(&im->tags, "tiff_resolutionunit", 0, resunit);
208 if (resunit == RESUNIT_NONE)
209 i_tags_addn(&im->tags, "i_aspect_only", 0, 1);
210 i_tags_set_float(&im->tags, "i_xres", 0, xres);
211 i_tags_set_float(&im->tags, "i_yres", 0, yres);
215 for (i = 0; i < text_tag_count; ++i) {
217 if (TIFFGetField(tif, text_tag_names[i].tag, &data)) {
218 mm_log((1, "i_readtiff_wiol: tag %d has value %s\n",
219 text_tag_names[i].tag, data));
220 i_tags_add(&im->tags, text_tag_names[i].name, 0, data,
225 i_tags_add(&im->tags, "i_format", 0, "tiff", -1, 0);
226 if (warn_buffer && *warn_buffer) {
227 i_tags_add(&im->tags, "i_warning", 0, warn_buffer, -1, 0);
231 /* TIFFPrintDirectory(tif, stdout, 0); good for debugging */
233 if (photometric == PHOTOMETRIC_PALETTE &&
234 (bits_per_sample == 4 || bits_per_sample == 8)) {
239 unsigned char *buffer;
241 if (!TIFFGetField(tif, TIFFTAG_COLORMAP, maps+0, maps+1, maps+2)) {
242 i_push_error(0, "Cannot get colormap for paletted image");
246 buffer = (unsigned char *)_TIFFmalloc(width+2);
248 i_push_error(0, "out of memory");
253 memset(used, 0, sizeof(used));
254 while (row < height && TIFFReadScanline(tif, buffer, row, 0) > 0) {
255 if (bits_per_sample == 4)
256 expand_4bit_hl(buffer, (width+1)/2);
257 for (col = 0; col < width; ++col) {
258 used[buffer[col]] = 1;
260 i_ppal(im, 0, width, row, buffer);
266 /* Ideally we'd optimize the palette, but that could be expensive
267 since we'd have to re-index every pixel.
269 Optimizing the palette (even at this level) might not
270 be what the user wants, so I don't do it.
272 We'll add a function to optimize a paletted image instead.
274 maxused = (1 << bits_per_sample)-1;
276 while (maxused >= 0 && !used[maxused])
279 for (i = 0; i < 1 << bits_per_sample; ++i) {
281 for (ch = 0; ch < 3; ++ch) {
282 c.channel[ch] = Sample16To8(maps[ch][i]);
284 i_addcolors(im, &c, 1);
292 uint32 tile_width, tile_height;
294 TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width);
295 TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height);
296 mm_log((1, "i_readtiff_wiol: tile_width=%d, tile_height=%d\n", tile_width, tile_height));
298 raster = (uint32*)_TIFFmalloc(tile_width * tile_height * sizeof (uint32));
301 i_push_error(0, "No space for raster buffer");
305 for( row = 0; row < height; row += tile_height ) {
306 for( col = 0; ok && col < width; col += tile_width ) {
307 uint32 i_row, x, newrows, newcols;
309 /* Read the tile into an RGBA array */
310 if (!TIFFReadRGBATile(tif, col, row, raster)) {
314 newrows = (row+tile_height > height) ? height-row : tile_height;
315 mm_log((1, "i_readtiff_wiol: newrows=%d\n", newrows));
316 newcols = (col+tile_width > width ) ? width-row : tile_width;
317 for( i_row = 0; i_row < tile_height; i_row++ ) {
318 for(x = 0; x < newcols; x++) {
320 uint32 temp = raster[x+tile_width*(tile_height-i_row-1)];
321 val.rgba.r = TIFFGetR(temp);
322 val.rgba.g = TIFFGetG(temp);
323 val.rgba.b = TIFFGetB(temp);
324 val.rgba.a = TIFFGetA(temp);
325 i_ppix(im, col+x, row+i_row, &val);
331 uint32 rowsperstrip, row;
332 int rc = TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
333 mm_log((1, "i_readtiff_wiol: rowsperstrip=%d rc = %d\n", rowsperstrip, rc));
335 if (rc != 1 || rowsperstrip==-1) {
336 rowsperstrip = height;
339 raster = (uint32*)_TIFFmalloc(width * rowsperstrip * sizeof (uint32));
342 i_push_error(0, "No space for raster buffer");
346 for( row = 0; row < height; row += rowsperstrip ) {
347 uint32 newrows, i_row;
349 if (!TIFFReadRGBAStrip(tif, row, raster)) {
354 newrows = (row+rowsperstrip > height) ? height-row : rowsperstrip;
355 mm_log((1, "newrows=%d\n", newrows));
357 for( i_row = 0; i_row < newrows; i_row++ ) {
359 for(x = 0; x<width; x++) {
361 uint32 temp = raster[x+width*(newrows-i_row-1)];
362 val.rgba.r = TIFFGetR(temp);
363 val.rgba.g = TIFFGetG(temp);
364 val.rgba.b = TIFFGetB(temp);
365 val.rgba.a = TIFFGetA(temp);
366 i_ppix(im, x, i_row+row, &val);
373 mm_log((1, "i_readtiff_wiol: error during reading\n"));
374 i_tags_addn(&im->tags, "i_incomplete", 0, 1);
383 =item i_readtiff_wiol(im, ig)
388 i_readtiff_wiol(io_glue *ig, int length) {
390 TIFFErrorHandler old_handler;
391 TIFFErrorHandler old_warn_handler;
395 old_handler = TIFFSetErrorHandler(error_handler);
396 old_warn_handler = TIFFSetWarningHandler(warn_handler);
400 /* Add code to get the filename info from the iolayer */
401 /* Also add code to check for mmapped code */
403 io_glue_commit_types(ig);
404 mm_log((1, "i_readtiff_wiol(ig %p, length %d)\n", ig, length));
406 tif = TIFFClientOpen("(Iolayer)",
409 (TIFFReadWriteProc) ig->readcb,
410 (TIFFReadWriteProc) ig->writecb,
411 (TIFFSeekProc) comp_seek,
412 (TIFFCloseProc) ig->closecb,
413 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
414 (TIFFMapFileProc) comp_mmap,
415 (TIFFUnmapFileProc) comp_munmap);
418 mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
419 i_push_error(0, "opening file");
420 TIFFSetErrorHandler(old_handler);
421 TIFFSetWarningHandler(old_warn_handler);
425 im = read_one_tiff(tif);
427 if (TIFFLastDirectory(tif)) mm_log((1, "Last directory of tiff file\n"));
428 TIFFSetErrorHandler(old_handler);
429 TIFFSetWarningHandler(old_warn_handler);
435 =item i_readtiff_multi_wiol(ig, length, *count)
437 Reads multiple images from a TIFF.
442 i_readtiff_multi_wiol(io_glue *ig, int length, int *count) {
444 TIFFErrorHandler old_handler;
445 TIFFErrorHandler old_warn_handler;
446 i_img **results = NULL;
447 int result_alloc = 0;
451 old_handler = TIFFSetErrorHandler(error_handler);
452 old_warn_handler = TIFFSetWarningHandler(warn_handler);
456 /* Add code to get the filename info from the iolayer */
457 /* Also add code to check for mmapped code */
459 io_glue_commit_types(ig);
460 mm_log((1, "i_readtiff_wiol(ig %p, length %d)\n", ig, length));
462 tif = TIFFClientOpen("(Iolayer)",
465 (TIFFReadWriteProc) ig->readcb,
466 (TIFFReadWriteProc) ig->writecb,
467 (TIFFSeekProc) comp_seek,
468 (TIFFCloseProc) ig->closecb,
469 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
470 (TIFFMapFileProc) comp_mmap,
471 (TIFFUnmapFileProc) comp_munmap);
474 mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
475 i_push_error(0, "opening file");
476 TIFFSetErrorHandler(old_handler);
477 TIFFSetWarningHandler(old_warn_handler);
483 i_img *im = read_one_tiff(tif);
486 if (++*count > result_alloc) {
487 if (result_alloc == 0) {
489 results = mymalloc(result_alloc * sizeof(i_img *));
494 newresults = myrealloc(results, result_alloc * sizeof(i_img *));
496 i_img_destroy(im); /* don't leak it */
499 results = newresults;
502 results[*count-1] = im;
503 } while (TIFFSetDirectory(tif, ++dirnum));
505 TIFFSetWarningHandler(old_warn_handler);
506 TIFFSetErrorHandler(old_handler);
512 i_writetiff_low_faxable(TIFF *tif, i_img *im, int fine) {
513 uint32 width, height;
514 unsigned char *linebuf = NULL;
520 float vres = fine ? 196 : 98;
526 switch (im->channels) {
536 /* This means a colorspace we don't handle yet */
537 mm_log((1, "i_writetiff_wiol_faxable: don't handle %d channel images.\n", im->channels));
541 /* Add code to get the filename info from the iolayer */
542 /* Also add code to check for mmapped code */
545 mm_log((1, "i_writetiff_wiol_faxable: width=%d, height=%d, channels=%d\n", width, height, im->channels));
547 if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width) )
548 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField width=%d failed\n", width)); return 0; }
549 if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height) )
550 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField length=%d failed\n", height)); return 0; }
551 if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1))
552 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField samplesperpixel=1 failed\n")); return 0; }
553 if (!TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT))
554 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Orientation=topleft\n")); return 0; }
555 if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 1) )
556 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField bitpersample=1\n")); return 0; }
557 if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG))
558 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField planarconfig\n")); return 0; }
559 if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK))
560 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField photometric=%d\n", PHOTOMETRIC_MINISBLACK)); return 0; }
561 if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, 3))
562 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField compression=3\n")); return 0; }
564 linebuf = (unsigned char *)_TIFFmalloc( TIFFScanlineSize(tif) );
566 if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, -1))) {
567 mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField rowsperstrip=-1\n")); return 0; }
569 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
570 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rc);
572 mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField rowsperstrip=%d\n", rowsperstrip));
573 mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField scanlinesize=%d\n", TIFFScanlineSize(tif) ));
574 mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG));
576 if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)204))
577 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Xresolution=204\n")); return 0; }
578 if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, vres))
579 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Yresolution=196\n")); return 0; }
580 if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH)) {
581 mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField ResolutionUnit=%d\n", RESUNIT_INCH)); return 0;
584 if (!save_tiff_tags(tif, im)) {
588 for (y=0; y<height; y++) {
590 for(x=0; x<width; x+=8) {
595 linebuf[linebufpos]=0;
596 bits = width-x; if(bits>8) bits=8;
597 i_gsamp(im, x, x+8, y, luma, &luma_chan, 1);
598 for(bitpos=0;bitpos<bits;bitpos++) {
599 linebuf[linebufpos] |= ((luma[bitpos]>=128)?bitval:0);
604 if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
605 mm_log((1, "i_writetiff_wiol_faxable: TIFFWriteScanline failed.\n"));
609 if (linebuf) _TIFFfree(linebuf);
615 i_writetiff_low(TIFF *tif, i_img *im) {
616 uint32 width, height;
618 uint16 predictor = 0;
620 int jpegcolormode = JPEGCOLORMODE_RGB;
621 uint16 compression = COMPRESSION_PACKBITS;
624 uint32 rowsperstrip = (uint32) -1; /* Let library pick default */
625 unsigned char *linebuf = NULL;
630 int got_xres, got_yres, got_aspectonly, aspect_only, resunit;
632 uint16 bitspersample = 8;
633 uint16 samplesperpixel;
634 uint16 *colors = NULL;
638 channels = im->channels;
642 photometric = PHOTOMETRIC_MINISBLACK;
645 photometric = PHOTOMETRIC_RGB;
646 if (compression == COMPRESSION_JPEG && jpegcolormode == JPEGCOLORMODE_RGB) photometric = PHOTOMETRIC_YCBCR;
647 else if (im->type == i_palette_type) {
648 photometric = PHOTOMETRIC_PALETTE;
652 /* This means a colorspace we don't handle yet */
653 mm_log((1, "i_writetiff_wiol: don't handle %d channel images.\n", channels));
657 /* Add code to get the filename info from the iolayer */
658 /* Also add code to check for mmapped code */
660 /*io_glue_commit_types(ig);*/
661 /*mm_log((1, "i_writetiff_wiol(im 0x%p, ig 0x%p)\n", im, ig));*/
663 mm_log((1, "i_writetiff_low: width=%d, height=%d, channels=%d\n", width, height, channels));
665 if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width) ) {
666 mm_log((1, "i_writetiff_wiol: TIFFSetField width=%d failed\n", width));
669 if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height) ) {
670 mm_log((1, "i_writetiff_wiol: TIFFSetField length=%d failed\n", height));
673 if (!TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT)) {
674 mm_log((1, "i_writetiff_wiol: TIFFSetField Orientation=topleft\n"));
677 if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) {
678 mm_log((1, "i_writetiff_wiol: TIFFSetField planarconfig\n"));
681 if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric)) {
682 mm_log((1, "i_writetiff_wiol: TIFFSetField photometric=%d\n", photometric));
685 if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, compression)) {
686 mm_log((1, "i_writetiff_wiol: TIFFSetField compression=%d\n", compression));
689 samplesperpixel = channels;
690 if (photometric == PHOTOMETRIC_PALETTE) {
693 int count = i_colorcount(im);
703 size = 1 << bitspersample;
704 colors = (uint16 *)_TIFFmalloc(sizeof(uint16) * 3 * size);
706 out[1] = colors + size;
707 out[2] = colors + 2 * size;
709 for (i = 0; i < count; ++i) {
710 i_getcolors(im, i, &c, 1);
711 for (ch = 0; ch < 3; ++ch)
712 out[ch][i] = c.channel[ch] * 257;
714 for (; i < size; ++i) {
715 for (ch = 0; ch < 3; ++ch)
718 if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitspersample)) {
719 mm_log((1, "i_writetiff_wiol: TIFFSetField bitpersample=%d\n",
723 if (!TIFFSetField(tif, TIFFTAG_COLORMAP, out[0], out[1], out[2])) {
724 mm_log((1, "i_writetiff_wiol: TIFFSetField colormap\n"));
729 if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitspersample)) {
730 mm_log((1, "i_writetiff_wiol: TIFFSetField bitpersample=%d\n",
735 if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel)) {
736 mm_log((1, "i_writetiff_wiol: TIFFSetField samplesperpixel=%d failed\n", samplesperpixel));
740 switch (compression) {
741 case COMPRESSION_JPEG:
742 mm_log((1, "i_writetiff_wiol: jpeg compression\n"));
743 if (!TIFFSetField(tif, TIFFTAG_JPEGQUALITY, quality) ) {
744 mm_log((1, "i_writetiff_wiol: TIFFSetField jpegquality=%d\n", quality));
747 if (!TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, jpegcolormode)) {
748 mm_log((1, "i_writetiff_wiol: TIFFSetField jpegcolormode=%d\n", jpegcolormode));
752 case COMPRESSION_LZW:
753 mm_log((1, "i_writetiff_wiol: lzw compression\n"));
755 case COMPRESSION_DEFLATE:
756 mm_log((1, "i_writetiff_wiol: deflate compression\n"));
758 if (!TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor)) {
759 mm_log((1, "i_writetiff_wiol: TIFFSetField predictor=%d\n", predictor));
763 case COMPRESSION_PACKBITS:
764 mm_log((1, "i_writetiff_wiol: packbits compression\n"));
767 mm_log((1, "i_writetiff_wiol: unknown compression %d\n", compression));
771 linebytes = channels * width;
772 linebytes = TIFFScanlineSize(tif) > linebytes ? linebytes
773 : TIFFScanlineSize(tif);
774 /* working space for the scanlines - we go from 8-bit/pixel to 4 */
775 if (photometric == PHOTOMETRIC_PALETTE && bitspersample == 4)
776 linebytes += linebytes + 1;
777 linebuf = (unsigned char *)_TIFFmalloc(linebytes);
779 if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, rowsperstrip))) {
780 mm_log((1, "i_writetiff_wiol: TIFFSetField rowsperstrip=%d\n", rowsperstrip)); return 0; }
782 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
783 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rc);
785 mm_log((1, "i_writetiff_wiol: TIFFGetField rowsperstrip=%d\n", rowsperstrip));
786 mm_log((1, "i_writetiff_wiol: TIFFGetField scanlinesize=%d\n", TIFFScanlineSize(tif) ));
787 mm_log((1, "i_writetiff_wiol: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG));
788 mm_log((1, "i_writetiff_wiol: bitspersample = %d\n", bitspersample));
790 got_xres = i_tags_get_float(&im->tags, "i_xres", 0, &xres);
791 got_yres = i_tags_get_float(&im->tags, "i_yres", 0, &yres);
792 if (!i_tags_get_int(&im->tags, "i_aspect_only", 0,&aspect_only))
794 if (!i_tags_get_int(&im->tags, "tiff_resolutionunit", 0, &resunit))
795 resunit = RESUNIT_INCH;
796 if (got_xres || got_yres) {
802 resunit = RESUNIT_NONE;
805 if (resunit == RESUNIT_CENTIMETER) {
810 resunit = RESUNIT_INCH;
813 if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)xres)) {
814 i_push_error(0, "cannot set TIFFTAG_XRESOLUTION tag");
817 if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)yres)) {
818 i_push_error(0, "cannot set TIFFTAG_YRESOLUTION tag");
821 if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (uint16)resunit)) {
822 i_push_error(0, "cannot set TIFFTAG_RESOLUTIONUNIT tag");
827 if (!save_tiff_tags(tif, im)) {
831 if (photometric == PHOTOMETRIC_PALETTE) {
832 for (y = 0; y < height; ++y) {
833 i_gpal(im, 0, width, y, linebuf);
834 if (bitspersample == 4)
835 pack_4bit_hl(linebuf, width);
836 if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
837 mm_log((1, "i_writetiff_wiol: TIFFWriteScanline failed.\n"));
838 if (linebuf) _TIFFfree(linebuf);
839 if (colors) _TIFFfree(colors);
845 for (y=0; y<height; y++) {
847 for(x=0; x<width; x++) {
848 (void) i_gpix(im, x, y,&val);
849 for(ch=0; ch<channels; ch++)
850 linebuf[ci++] = val.channel[ch];
852 if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
853 mm_log((1, "i_writetiff_wiol: TIFFWriteScanline failed.\n"));
854 if (linebuf) _TIFFfree(linebuf);
855 if (colors) _TIFFfree(colors);
860 if (linebuf) _TIFFfree(linebuf);
861 if (colors) _TIFFfree(colors);
866 =item i_writetiff_multi_wiol(ig, imgs, count, fine_mode)
868 Stores an image in the iolayer object.
870 ig - io_object that defines source to write to
871 imgs,count - the images to write
877 i_writetiff_multi_wiol(io_glue *ig, i_img **imgs, int count) {
881 io_glue_commit_types(ig);
883 mm_log((1, "i_writetiff_multi_wiol(ig 0x%p, imgs 0x%p, count %d)\n",
886 /* FIXME: Enable the mmap interface */
888 tif = TIFFClientOpen("No name",
891 (TIFFReadWriteProc) ig->readcb,
892 (TIFFReadWriteProc) ig->writecb,
893 (TIFFSeekProc) comp_seek,
894 (TIFFCloseProc) ig->closecb,
895 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
896 (TIFFMapFileProc) comp_mmap,
897 (TIFFUnmapFileProc) comp_munmap);
902 mm_log((1, "i_writetiff_mulit_wiol: Unable to open tif file for writing\n"));
906 for (i = 0; i < count; ++i) {
907 if (!i_writetiff_low(tif, imgs[i])) {
912 if (!TIFFWriteDirectory(tif)) {
913 i_push_error(0, "Cannot write TIFF directory");
919 (void) TIFFClose(tif);
924 =item i_writetiff_multi_wiol_faxable(ig, imgs, count, fine_mode)
926 Stores an image in the iolayer object.
928 ig - io_object that defines source to write to
929 imgs,count - the images to write
930 fine_mode - select fine or normal mode fax images
937 i_writetiff_multi_wiol_faxable(io_glue *ig, i_img **imgs, int count, int fine) {
941 io_glue_commit_types(ig);
943 mm_log((1, "i_writetiff_multi_wiol(ig 0x%p, imgs 0x%p, count %d)\n",
946 /* FIXME: Enable the mmap interface */
948 tif = TIFFClientOpen("No name",
951 (TIFFReadWriteProc) ig->readcb,
952 (TIFFReadWriteProc) ig->writecb,
953 (TIFFSeekProc) comp_seek,
954 (TIFFCloseProc) ig->closecb,
955 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
956 (TIFFMapFileProc) comp_mmap,
957 (TIFFUnmapFileProc) comp_munmap);
962 mm_log((1, "i_writetiff_mulit_wiol: Unable to open tif file for writing\n"));
966 for (i = 0; i < count; ++i) {
967 if (!i_writetiff_low_faxable(tif, imgs[i], fine)) {
972 if (!TIFFWriteDirectory(tif)) {
973 i_push_error(0, "Cannot write TIFF directory");
979 (void) TIFFClose(tif);
984 =item i_writetiff_wiol(im, ig)
986 Stores an image in the iolayer object.
988 im - image object to write out
989 ig - io_object that defines source to write to
994 i_writetiff_wiol(i_img *img, io_glue *ig) {
998 io_glue_commit_types(ig);
1000 mm_log((1, "i_writetiff_wiol(img %p, ig 0x%p)\n", img, ig));
1002 /* FIXME: Enable the mmap interface */
1004 tif = TIFFClientOpen("No name",
1007 (TIFFReadWriteProc) ig->readcb,
1008 (TIFFReadWriteProc) ig->writecb,
1009 (TIFFSeekProc) comp_seek,
1010 (TIFFCloseProc) ig->closecb,
1011 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
1012 (TIFFMapFileProc) comp_mmap,
1013 (TIFFUnmapFileProc) comp_munmap);
1018 mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
1022 if (!i_writetiff_low(tif, img)) {
1027 (void) TIFFClose(tif);
1034 =item i_writetiff_wiol_faxable(i_img *, io_glue *)
1036 Stores an image in the iolayer object in faxable tiff format.
1038 im - image object to write out
1039 ig - io_object that defines source to write to
1041 Note, this may be rewritten to use to simply be a call to a
1042 lower-level function that gives more options for writing tiff at some
1049 i_writetiff_wiol_faxable(i_img *im, io_glue *ig, int fine) {
1053 io_glue_commit_types(ig);
1055 mm_log((1, "i_writetiff_wiol(img %p, ig 0x%p)\n", im, ig));
1057 /* FIXME: Enable the mmap interface */
1059 tif = TIFFClientOpen("No name",
1062 (TIFFReadWriteProc) ig->readcb,
1063 (TIFFReadWriteProc) ig->writecb,
1064 (TIFFSeekProc) comp_seek,
1065 (TIFFCloseProc) ig->closecb,
1066 ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
1067 (TIFFMapFileProc) comp_mmap,
1068 (TIFFUnmapFileProc) comp_munmap);
1073 mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
1077 if (!i_writetiff_low_faxable(tif, im, fine)) {
1082 (void) TIFFClose(tif);
1086 static int save_tiff_tags(TIFF *tif, i_img *im) {
1089 for (i = 0; i < text_tag_count; ++i) {
1091 if (i_tags_find(&im->tags, text_tag_names[i].name, 0, &entry)) {
1092 if (!TIFFSetField(tif, text_tag_names[i].tag,
1093 im->tags.tags[entry].data)) {
1094 i_push_errorf(0, "cannot save %s to TIFF", text_tag_names[i].name);
1105 =item expand_4bit_hl(buf, count)
1107 Expands 4-bit/entry packed data into 1 byte/entry.
1109 buf must contain count bytes to be expanded and have 2*count bytes total
1112 The data is expanded in place.
1117 static void expand_4bit_hl(unsigned char *buf, int count) {
1118 while (--count >= 0) {
1119 buf[count*2+1] = buf[count] & 0xF;
1120 buf[count*2] = buf[count] >> 4;
1124 static void pack_4bit_hl(unsigned char *buf, int count) {
1127 buf[i/2] = (buf[i] << 4) + buf[i+1];
1137 Arnar M. Hrafnkelsson <addi@umich.edu>