]> git.imager.perl.org - imager.git/blob - tiff.c
add to_rgb16 method
[imager.git] / tiff.c
1 #include "imager.h"
2 #include "tiffio.h"
3 #include "iolayer.h"
4 #include "imageri.h"
5
6 /*
7 =head1 NAME
8
9 tiff.c - implements reading and writing tiff files, uses io layer.
10
11 =head1 SYNOPSIS
12
13    io_glue *ig = io_new_fd( fd );
14    i_img *im   = i_readtiff_wiol(ig, -1); // no limit on how much is read
15    // or 
16    io_glue *ig = io_new_fd( fd );
17    return_code = i_writetiff_wiol(im, ig); 
18
19 =head1 DESCRIPTION
20
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
23 memory mapped buffer.
24
25 =head1 FUNCTION REFERENCE
26
27 Some of these functions are internal.
28
29 =over
30
31 =cut
32 */
33
34 #define byteswap_macro(x) \
35      ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >>  8) |     \
36       (((x) & 0x0000ff00) <<  8) | (((x) & 0x000000ff) << 24))
37
38 struct tag_name {
39   char *name;
40   uint32 tag;
41 };
42
43 static struct tag_name text_tag_names[] =
44 {
45   { "tiff_documentname", TIFFTAG_DOCUMENTNAME, },
46   { "tiff_imagedescription", TIFFTAG_IMAGEDESCRIPTION, },
47   { "tiff_make", TIFFTAG_MAKE, },
48   { "tiff_model", TIFFTAG_MODEL, },
49   { "tiff_pagename", TIFFTAG_PAGENAME, },
50   { "tiff_software", TIFFTAG_SOFTWARE, },
51   { "tiff_datetime", TIFFTAG_DATETIME, },
52   { "tiff_artist", TIFFTAG_ARTIST, },
53   { "tiff_hostcomputer", TIFFTAG_HOSTCOMPUTER, },
54 };
55
56 static const int text_tag_count = 
57   sizeof(text_tag_names) / sizeof(*text_tag_names);
58
59 static void error_handler(char const *module, char const *fmt, va_list ap) {
60   i_push_errorvf(0, fmt, ap);
61 }
62
63 #define WARN_BUFFER_LIMIT 10000
64 static char *warn_buffer = NULL;
65 static int warn_buffer_size = 0;
66
67 static void warn_handler(char const *module, char const *fmt, va_list ap) {
68   char buf[1000];
69
70   buf[0] = '\0';
71 #ifdef HAVE_SNPRINTF
72   vsnprintf(buf, sizeof(buf), fmt, ap);
73 #else
74   vsprintf(buf, fmt, ap);
75 #endif
76   if (!warn_buffer || strlen(warn_buffer)+strlen(buf)+2 > warn_buffer_size) {
77     int new_size = warn_buffer_size + strlen(buf) + 2;
78     char *old_buffer = warn_buffer;
79     if (new_size > WARN_BUFFER_LIMIT) {
80       new_size = WARN_BUFFER_LIMIT;
81     }
82     warn_buffer = myrealloc(warn_buffer, new_size);
83     if (!old_buffer) *warn_buffer = '\0';
84     warn_buffer_size = new_size;
85   }
86   if (strlen(warn_buffer)+strlen(buf)+2 <= warn_buffer_size) {
87     strcat(warn_buffer, buf);
88     strcat(warn_buffer, "\n");
89   }
90 }
91
92 static int save_tiff_tags(TIFF *tif, i_img *im);
93
94 static void expand_4bit_hl(unsigned char *buf, int count);
95
96 static void pack_4bit_hl(unsigned char *buf, int count);
97
98
99 static toff_t sizeproc(thandle_t x) {
100         return 0;
101 }
102
103
104 /*
105 =item comp_seek(h, o, w)
106
107 Compatability for 64 bit systems like latest freebsd (internal)
108
109    h - tiff handle, cast an io_glue object
110    o - offset
111    w - whence
112
113 =cut
114 */
115
116 static
117 toff_t
118 comp_seek(thandle_t h, toff_t o, int w) {
119   io_glue *ig = (io_glue*)h;
120   return (toff_t) ig->seekcb(ig, o, w);
121 }
122
123 /*
124 =item comp_mmap(thandle_t, tdata_t*, toff_t*)
125
126 Dummy mmap stub.
127
128 This shouldn't ever be called but newer tifflibs want it anyway.
129
130 =cut
131 */
132
133 static 
134 int
135 comp_mmap(thandle_t h, tdata_t*p, toff_t*off) {
136   return -1;
137 }
138
139 /*
140 =item comp_munmap(thandle_t h, tdata_t p, toff_t off)
141
142 Dummy munmap stub.
143
144 This shouldn't ever be called but newer tifflibs want it anyway.
145
146 =cut
147 */
148
149 static void
150 comp_munmap(thandle_t h, tdata_t p, toff_t off) {
151   /* do nothing */
152 }
153
154 static i_img *read_one_tiff(TIFF *tif, int allow_incomplete) {
155   i_img *im;
156   uint32 width, height;
157   uint16 channels;
158   uint32* raster = NULL;
159   int tiled, error;
160   float xres, yres;
161   uint16 resunit;
162   int gotXres, gotYres;
163   uint16 photometric;
164   uint16 bits_per_sample;
165   int i;
166   int ch;
167
168   error = 0;
169
170   TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
171   TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
172   TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &channels);
173   tiled = TIFFIsTiled(tif);
174   TIFFGetFieldDefaulted(tif, TIFFTAG_PHOTOMETRIC, &photometric);
175   TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
176
177   mm_log((1, "i_readtiff_wiol: width=%d, height=%d, channels=%d\n", width, height, channels));
178   mm_log((1, "i_readtiff_wiol: %stiled\n", tiled?"":"not "));
179   mm_log((1, "i_readtiff_wiol: %sbyte swapped\n", TIFFIsByteSwapped(tif)?"":"not "));
180
181   /* separated defaults to CMYK, but if the user is using some strange
182      ink system we can't work out the color anyway */
183   if (photometric == PHOTOMETRIC_SEPARATED && channels >= 4) {
184     /* TIFF can have more than one alpha channel on an image,
185        but Imager can't, only store the first one */
186     
187     channels = channels == 4 ? 3 : 4;
188
189     /* unfortunately the RGBA functions don't try to deal with the alpha
190        channel on CMYK images, at some point I'm planning on expanding
191        TIFF support to handle 16-bit/sample images and I'll deal with
192        it then */
193   }
194
195   /* TIFF images can have more than one alpha channel, but Imager can't
196      this ignores the possibility of 2 channel images with 2 alpha,
197      but there's not much I can do about that */
198   if (channels > 4)
199     channels = 4;
200
201   if (photometric == PHOTOMETRIC_PALETTE && bits_per_sample <= 8) {
202     channels = 3;
203     im = i_img_pal_new(width, height, channels, 256);
204   }
205   else {
206     im = i_img_empty_ch(NULL, width, height, channels);
207   }
208
209   if (!im)
210     return NULL;
211
212   /* general metadata */
213   i_tags_addn(&im->tags, "tiff_bitspersample", 0, bits_per_sample);
214   i_tags_addn(&im->tags, "tiff_photometric", 0, photometric);
215     
216   /* resolution tags */
217   TIFFGetFieldDefaulted(tif, TIFFTAG_RESOLUTIONUNIT, &resunit);
218   gotXres = TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres);
219   gotYres = TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres);
220   if (gotXres || gotYres) {
221     if (!gotXres)
222       xres = yres;
223     else if (!gotYres)
224       yres = xres;
225     i_tags_addn(&im->tags, "tiff_resolutionunit", 0, resunit);
226     if (resunit == RESUNIT_CENTIMETER) {
227       /* from dots per cm to dpi */
228       xres *= 2.54;
229       yres *= 2.54;
230       i_tags_add(&im->tags, "tiff_resolutionunit_name", 0, "centimeter", -1, 0);
231     }
232     else if (resunit == RESUNIT_NONE) {
233       i_tags_addn(&im->tags, "i_aspect_only", 0, 1);
234       i_tags_add(&im->tags, "tiff_resolutionunit_name", 0, "none", -1, 0);
235     }
236     else if (resunit == RESUNIT_INCH) {
237       i_tags_add(&im->tags, "tiff_resolutionunit_name", 0, "inch", -1, 0);
238     }
239     else {
240       i_tags_add(&im->tags, "tiff_resolutionunit_name", 0, "unknown", -1, 0);
241     }
242     /* tifflib doesn't seem to provide a way to get to the original rational
243        value of these, which would let me provide a more reasonable
244        precision. So make up a number. */
245     i_tags_set_float2(&im->tags, "i_xres", 0, xres, 6);
246     i_tags_set_float2(&im->tags, "i_yres", 0, yres, 6);
247   }
248
249   /* Text tags */
250   for (i = 0; i < text_tag_count; ++i) {
251     char *data;
252     if (TIFFGetField(tif, text_tag_names[i].tag, &data)) {
253       mm_log((1, "i_readtiff_wiol: tag %d has value %s\n", 
254               text_tag_names[i].tag, data));
255       i_tags_add(&im->tags, text_tag_names[i].name, 0, data, 
256                  strlen(data), 0);
257     }
258   }
259
260   i_tags_add(&im->tags, "i_format", 0, "tiff", -1, 0);
261   if (warn_buffer && *warn_buffer) {
262     i_tags_add(&im->tags, "i_warning", 0, warn_buffer, -1, 0);
263     *warn_buffer = '\0';
264   }
265   
266   /*   TIFFPrintDirectory(tif, stdout, 0); good for debugging */
267
268   if (photometric == PHOTOMETRIC_PALETTE &&
269       (bits_per_sample == 4 || bits_per_sample == 8)) {
270     uint16 *maps[3];
271     char used[256];
272     int maxused;
273     uint32 row, col;
274     unsigned char *buffer;
275
276     if (!TIFFGetField(tif, TIFFTAG_COLORMAP, maps+0, maps+1, maps+2)) {
277       i_push_error(0, "Cannot get colormap for paletted image");
278       i_img_destroy(im);
279       return NULL;
280     }
281     buffer = (unsigned char *)_TIFFmalloc(width+2);
282     if (!buffer) {
283       i_push_error(0, "out of memory");
284       i_img_destroy(im);
285       return NULL;
286     }
287     row = 0;
288     memset(used, 0, sizeof(used));
289     while (row < height && TIFFReadScanline(tif, buffer, row, 0) > 0) {
290       if (bits_per_sample == 4)
291         expand_4bit_hl(buffer, (width+1)/2);
292       for (col = 0; col < width; ++col) {
293         used[buffer[col]] = 1;
294       }
295       i_ppal(im, 0, width, row, buffer);
296       ++row;
297     }
298     if (row < height) {
299       if (allow_incomplete) {
300         i_tags_setn(&im->tags, "i_lines_read", row);
301       }
302       else {
303         i_img_destroy(im);
304         _TIFFfree(buffer);
305         return NULL;
306       }
307       error = 1;
308     }
309     /* Ideally we'd optimize the palette, but that could be expensive
310        since we'd have to re-index every pixel.
311
312        Optimizing the palette (even at this level) might not 
313        be what the user wants, so I don't do it.
314
315        We'll add a function to optimize a paletted image instead.
316     */
317     maxused = (1 << bits_per_sample)-1;
318     if (!error) {
319       while (maxused >= 0 && !used[maxused])
320         --maxused;
321     }
322     for (i = 0; i < 1 << bits_per_sample; ++i) {
323       i_color c;
324       for (ch = 0; ch < 3; ++ch) {
325         c.channel[ch] = Sample16To8(maps[ch][i]);
326       }
327       i_addcolors(im, &c, 1);
328     }
329     _TIFFfree(buffer);
330   }
331   else {
332     if (tiled) {
333       int ok = 1;
334       uint32 row, col;
335       uint32 tile_width, tile_height;
336       
337       TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width);
338       TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height);
339       mm_log((1, "i_readtiff_wiol: tile_width=%d, tile_height=%d\n", tile_width, tile_height));
340       
341       raster = (uint32*)_TIFFmalloc(tile_width * tile_height * sizeof (uint32));
342       if (!raster) {
343         i_img_destroy(im);
344         i_push_error(0, "No space for raster buffer");
345         return NULL;
346       }
347       
348       for( row = 0; row < height; row += tile_height ) {
349         for( col = 0; ok && col < width; col += tile_width ) {
350           uint32 i_row, x, newrows, newcols;
351           
352           /* Read the tile into an RGBA array */
353           if (!TIFFReadRGBATile(tif, col, row, raster)) {
354             ok = 0;
355             break;
356           }
357           newrows = (row+tile_height > height) ? height-row : tile_height;
358           mm_log((1, "i_readtiff_wiol: newrows=%d\n", newrows));
359           newcols = (col+tile_width  > width ) ? width-row  : tile_width;
360           for( i_row = 0; i_row < tile_height; i_row++ ) {
361             for(x = 0; x < newcols; x++) {
362               i_color val;
363               uint32 temp = raster[x+tile_width*(tile_height-i_row-1)];
364               val.rgba.r = TIFFGetR(temp);
365               val.rgba.g = TIFFGetG(temp);
366               val.rgba.b = TIFFGetB(temp);
367               val.rgba.a = TIFFGetA(temp);
368               i_ppix(im, col+x, row+i_row, &val);
369             }
370           }
371         }
372       }
373     } else {
374       uint32 rowsperstrip, row;
375       int rc = TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
376       mm_log((1, "i_readtiff_wiol: rowsperstrip=%d rc = %d\n", rowsperstrip, rc));
377   
378                         if (rc != 1 || rowsperstrip==-1) {
379                                 rowsperstrip = height;
380                         }
381     
382       raster = (uint32*)_TIFFmalloc(width * rowsperstrip * sizeof (uint32));
383       if (!raster) {
384         i_img_destroy(im);
385         i_push_error(0, "No space for raster buffer");
386         return NULL;
387       }
388       
389       for( row = 0; row < height; row += rowsperstrip ) {
390         uint32 newrows, i_row;
391         
392         if (!TIFFReadRGBAStrip(tif, row, raster)) {
393           if (allow_incomplete) {
394             i_tags_setn(&im->tags, "i_lines_read", row);
395             error++;
396             break;
397           }
398           else {
399             i_push_error(0, "could not read TIFF image strip");
400             _TIFFfree(raster);
401             i_img_destroy(im);
402             return NULL;
403           }
404         }
405         
406         newrows = (row+rowsperstrip > height) ? height-row : rowsperstrip;
407         mm_log((1, "newrows=%d\n", newrows));
408         
409         for( i_row = 0; i_row < newrows; i_row++ ) { 
410           uint32 x;
411           for(x = 0; x<width; x++) {
412             i_color val;
413             uint32 temp = raster[x+width*(newrows-i_row-1)];
414             val.rgba.r = TIFFGetR(temp);
415             val.rgba.g = TIFFGetG(temp);
416             val.rgba.b = TIFFGetB(temp);
417             val.rgba.a = TIFFGetA(temp);
418             i_ppix(im, x, i_row+row, &val);
419           }
420         }
421       }
422     }
423   }
424   if (error) {
425     mm_log((1, "i_readtiff_wiol: error during reading\n"));
426     i_tags_setn(&im->tags, "i_incomplete", 1);
427   }
428   if (raster)
429     _TIFFfree( raster );
430
431   return im;
432 }
433
434 /*
435 =item i_readtiff_wiol(im, ig)
436
437 =cut
438 */
439 i_img*
440 i_readtiff_wiol(io_glue *ig, int allow_incomplete, int page) {
441   TIFF* tif;
442   TIFFErrorHandler old_handler;
443   TIFFErrorHandler old_warn_handler;
444   i_img *im;
445
446   i_clear_error();
447   old_handler = TIFFSetErrorHandler(error_handler);
448   old_warn_handler = TIFFSetWarningHandler(warn_handler);
449   if (warn_buffer)
450     *warn_buffer = '\0';
451
452   /* Add code to get the filename info from the iolayer */
453   /* Also add code to check for mmapped code */
454
455   io_glue_commit_types(ig);
456   mm_log((1, "i_readtiff_wiol(ig %p, allow_incomplete %d, page %d)\n", ig, allow_incomplete, page));
457   
458   tif = TIFFClientOpen("(Iolayer)", 
459                        "rm", 
460                        (thandle_t) ig,
461                        (TIFFReadWriteProc) ig->readcb,
462                        (TIFFReadWriteProc) ig->writecb,
463                        (TIFFSeekProc) comp_seek,
464                        (TIFFCloseProc) ig->closecb,
465                        ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
466                        (TIFFMapFileProc) comp_mmap,
467                        (TIFFUnmapFileProc) comp_munmap);
468   
469   if (!tif) {
470     mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
471     i_push_error(0, "Error opening file");
472     TIFFSetErrorHandler(old_handler);
473     TIFFSetWarningHandler(old_warn_handler);
474     return NULL;
475   }
476
477   if (page != 0) {
478     if (!TIFFSetDirectory(tif, page)) {
479       mm_log((1, "i_readtiff_wiol: Unable to switch to directory %d\n", page));
480       i_push_errorf(0, "could not switch to page %d", page);
481       TIFFSetErrorHandler(old_handler);
482       TIFFSetWarningHandler(old_warn_handler);
483       TIFFClose(tif);
484       return NULL;
485     }
486   }
487
488   im = read_one_tiff(tif, allow_incomplete);
489
490   if (TIFFLastDirectory(tif)) mm_log((1, "Last directory of tiff file\n"));
491   TIFFSetErrorHandler(old_handler);
492   TIFFSetWarningHandler(old_warn_handler);
493   TIFFClose(tif);
494   return im;
495 }
496
497 /*
498 =item i_readtiff_multi_wiol(ig, length, *count)
499
500 Reads multiple images from a TIFF.
501
502 =cut
503 */
504 i_img**
505 i_readtiff_multi_wiol(io_glue *ig, int length, int *count) {
506   TIFF* tif;
507   TIFFErrorHandler old_handler;
508   TIFFErrorHandler old_warn_handler;
509   i_img **results = NULL;
510   int result_alloc = 0;
511   int dirnum = 0;
512
513   i_clear_error();
514   old_handler = TIFFSetErrorHandler(error_handler);
515   old_warn_handler = TIFFSetWarningHandler(warn_handler);
516   if (warn_buffer)
517     *warn_buffer = '\0';
518
519   /* Add code to get the filename info from the iolayer */
520   /* Also add code to check for mmapped code */
521
522   io_glue_commit_types(ig);
523   mm_log((1, "i_readtiff_wiol(ig %p, length %d)\n", ig, length));
524   
525   tif = TIFFClientOpen("(Iolayer)", 
526                        "rm", 
527                        (thandle_t) ig,
528                        (TIFFReadWriteProc) ig->readcb,
529                        (TIFFReadWriteProc) ig->writecb,
530                        (TIFFSeekProc) comp_seek,
531                        (TIFFCloseProc) ig->closecb,
532                        ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
533                        (TIFFMapFileProc) comp_mmap,
534                        (TIFFUnmapFileProc) comp_munmap);
535   
536   if (!tif) {
537     mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
538     i_push_error(0, "Error opening file");
539     TIFFSetErrorHandler(old_handler);
540     TIFFSetWarningHandler(old_warn_handler);
541     return NULL;
542   }
543
544   *count = 0;
545   do {
546     i_img *im = read_one_tiff(tif, 0);
547     if (!im)
548       break;
549     if (++*count > result_alloc) {
550       if (result_alloc == 0) {
551         result_alloc = 5;
552         results = mymalloc(result_alloc * sizeof(i_img *));
553       }
554       else {
555         i_img **newresults;
556         result_alloc *= 2;
557         newresults = myrealloc(results, result_alloc * sizeof(i_img *));
558         if (!newresults) {
559           i_img_destroy(im); /* don't leak it */
560           break;
561         }
562         results = newresults;
563       }
564     }
565     results[*count-1] = im;
566   } while (TIFFSetDirectory(tif, ++dirnum));
567
568   TIFFSetWarningHandler(old_warn_handler);
569   TIFFSetErrorHandler(old_handler);
570   TIFFClose(tif);
571   return results;
572 }
573
574 undef_int
575 i_writetiff_low_faxable(TIFF *tif, i_img *im, int fine) {
576   uint32 width, height;
577   unsigned char *linebuf = NULL;
578   uint32 y;
579   int rc;
580   uint32 x;
581   uint32 rowsperstrip;
582   float vres = fine ? 196 : 98;
583   int luma_chan;
584
585   width    = im->xsize;
586   height   = im->ysize;
587
588   switch (im->channels) {
589   case 1:
590   case 2:
591     luma_chan = 0;
592     break;
593   case 3:
594   case 4:
595     luma_chan = 1;
596     break;
597   default:
598     /* This means a colorspace we don't handle yet */
599     mm_log((1, "i_writetiff_wiol_faxable: don't handle %d channel images.\n", im->channels));
600     return 0;
601   }
602
603   /* Add code to get the filename info from the iolayer */
604   /* Also add code to check for mmapped code */
605
606
607   mm_log((1, "i_writetiff_wiol_faxable: width=%d, height=%d, channels=%d\n", width, height, im->channels));
608   
609   if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH,      width)   )
610     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField width=%d failed\n", width)); return 0; }
611   if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH,     height)  )
612     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField length=%d failed\n", height)); return 0; }
613   if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1))
614     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField samplesperpixel=1 failed\n")); return 0; }
615   if (!TIFFSetField(tif, TIFFTAG_ORIENTATION,  ORIENTATION_TOPLEFT))
616     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Orientation=topleft\n")); return 0; }
617   if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,   1)        )
618     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField bitpersample=1\n")); return 0; }
619   if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG))
620     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField planarconfig\n")); return 0; }
621   if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE))
622     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField photometric=%d\n", PHOTOMETRIC_MINISBLACK)); return 0; }
623   if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, 3))
624     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField compression=3\n")); return 0; }
625
626   linebuf = (unsigned char *)_TIFFmalloc( TIFFScanlineSize(tif) );
627   
628   if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, -1))) {
629     mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField rowsperstrip=-1\n")); return 0; }
630
631   TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
632   TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rc);
633
634   mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField rowsperstrip=%d\n", rowsperstrip));
635   mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField scanlinesize=%d\n", TIFFScanlineSize(tif) ));
636   mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG));
637
638   if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)204))
639     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Xresolution=204\n")); return 0; }
640   if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, vres))
641     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Yresolution=196\n")); return 0; }
642   if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH)) {
643     mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField ResolutionUnit=%d\n", RESUNIT_INCH)); return 0; 
644   }
645
646   if (!save_tiff_tags(tif, im)) {
647     return 0;
648   }
649
650   for (y=0; y<height; y++) {
651     int linebufpos=0;
652     for(x=0; x<width; x+=8) { 
653       int bits;
654       int bitpos;
655       i_sample_t luma[8];
656       uint8 bitval = 128;
657       linebuf[linebufpos]=0;
658       bits = width-x; if(bits>8) bits=8;
659       i_gsamp(im, x, x+8, y, luma, &luma_chan, 1);
660       for(bitpos=0;bitpos<bits;bitpos++) {
661         linebuf[linebufpos] |= ((luma[bitpos] < 128) ? bitval : 0);
662         bitval >>= 1;
663       }
664       linebufpos++;
665     }
666     if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
667       mm_log((1, "i_writetiff_wiol_faxable: TIFFWriteScanline failed.\n"));
668       break;
669     }
670   }
671   if (linebuf) _TIFFfree(linebuf);
672
673   return 1;
674 }
675
676 undef_int
677 i_writetiff_low(TIFF *tif, i_img *im) {
678   uint32 width, height;
679   uint16 channels;
680   uint16 predictor = 0;
681   int quality = 75;
682   int jpegcolormode = JPEGCOLORMODE_RGB;
683   uint16 compression = COMPRESSION_PACKBITS;
684   i_color val;
685   uint16 photometric;
686   uint32 rowsperstrip = (uint32) -1;  /* Let library pick default */
687   unsigned char *linebuf = NULL;
688   uint32 y;
689   tsize_t linebytes;
690   int ch, ci, rc;
691   uint32 x;
692   int got_xres, got_yres, aspect_only, resunit;
693   double xres, yres;
694   uint16 bitspersample = 8;
695   uint16 samplesperpixel;
696   uint16 *colors = NULL;
697
698   width    = im->xsize;
699   height   = im->ysize;
700   channels = im->channels;
701
702   switch (channels) {
703   case 1:
704     photometric = PHOTOMETRIC_MINISBLACK;
705     break;
706   case 3:
707     photometric = PHOTOMETRIC_RGB;
708     if (compression == COMPRESSION_JPEG && jpegcolormode == JPEGCOLORMODE_RGB) photometric = PHOTOMETRIC_YCBCR;
709     else if (im->type == i_palette_type) {
710       photometric = PHOTOMETRIC_PALETTE;
711     }
712     break;
713   default:
714     /* This means a colorspace we don't handle yet */
715     mm_log((1, "i_writetiff_wiol: don't handle %d channel images.\n", channels));
716     return 0;
717   }
718
719   /* Add code to get the filename info from the iolayer */
720   /* Also add code to check for mmapped code */
721
722   /*io_glue_commit_types(ig);*/
723   /*mm_log((1, "i_writetiff_wiol(im 0x%p, ig 0x%p)\n", im, ig));*/
724
725   mm_log((1, "i_writetiff_low: width=%d, height=%d, channels=%d\n", width, height, channels));
726   
727   if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH,      width)   ) { 
728     mm_log((1, "i_writetiff_wiol: TIFFSetField width=%d failed\n", width)); 
729     return 0; 
730   }
731   if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH,     height)  ) { 
732     mm_log((1, "i_writetiff_wiol: TIFFSetField length=%d failed\n", height)); 
733     return 0; 
734   }
735   if (!TIFFSetField(tif, TIFFTAG_ORIENTATION,  ORIENTATION_TOPLEFT)) {
736     mm_log((1, "i_writetiff_wiol: TIFFSetField Orientation=topleft\n")); 
737     return 0; 
738   }
739   if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) { 
740     mm_log((1, "i_writetiff_wiol: TIFFSetField planarconfig\n")); 
741     return 0; 
742   }
743   if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC,   photometric)) { 
744     mm_log((1, "i_writetiff_wiol: TIFFSetField photometric=%d\n", photometric)); 
745     return 0; 
746   }
747   if (!TIFFSetField(tif, TIFFTAG_COMPRESSION,   compression)) { 
748     mm_log((1, "i_writetiff_wiol: TIFFSetField compression=%d\n", compression)); 
749     return 0; 
750   }
751   samplesperpixel = channels;
752   if (photometric == PHOTOMETRIC_PALETTE) {
753     uint16 *out[3];
754     i_color c;
755     int count = i_colorcount(im);
756     int size;
757     int ch, i;
758     
759     samplesperpixel = 1;
760     if (count > 16)
761       bitspersample = 8;
762     else
763       bitspersample = 4;
764     size = 1 << bitspersample;
765     colors = (uint16 *)_TIFFmalloc(sizeof(uint16) * 3 * size);
766     out[0] = colors;
767     out[1] = colors + size;
768     out[2] = colors + 2 * size;
769     
770     for (i = 0; i < count; ++i) {
771       i_getcolors(im, i, &c, 1);
772       for (ch = 0; ch < 3; ++ch)
773         out[ch][i] = c.channel[ch] * 257;
774     }
775     for (; i < size; ++i) {
776       for (ch = 0; ch < 3; ++ch)
777         out[ch][i] = 0;
778     }
779     if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitspersample)) { 
780       mm_log((1, "i_writetiff_wiol: TIFFSetField bitpersample=%d\n", 
781               bitspersample)); 
782       return 0;
783     }
784     if (!TIFFSetField(tif, TIFFTAG_COLORMAP, out[0], out[1], out[2])) {
785       mm_log((1, "i_writetiff_wiol: TIFFSetField colormap\n")); 
786       return 0;
787     }
788   }
789   else {
790     if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bitspersample)) { 
791       mm_log((1, "i_writetiff_wiol: TIFFSetField bitpersample=%d\n", 
792               bitspersample)); 
793       return 0;
794     }
795   }
796   if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel)) { 
797     mm_log((1, "i_writetiff_wiol: TIFFSetField samplesperpixel=%d failed\n", samplesperpixel)); 
798     return 0;
799   }
800
801   switch (compression) {
802   case COMPRESSION_JPEG:
803     mm_log((1, "i_writetiff_wiol: jpeg compression\n"));
804     if (!TIFFSetField(tif, TIFFTAG_JPEGQUALITY, quality)        ) { 
805       mm_log((1, "i_writetiff_wiol: TIFFSetField jpegquality=%d\n", quality));
806       return 0; 
807     }
808     if (!TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, jpegcolormode)) { 
809       mm_log((1, "i_writetiff_wiol: TIFFSetField jpegcolormode=%d\n", jpegcolormode)); 
810       return 0; 
811     }
812     break;
813   case COMPRESSION_LZW:
814     mm_log((1, "i_writetiff_wiol: lzw compression\n"));
815     break;
816   case COMPRESSION_DEFLATE:
817     mm_log((1, "i_writetiff_wiol: deflate compression\n"));
818     if (predictor != 0) 
819       if (!TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor)) { 
820         mm_log((1, "i_writetiff_wiol: TIFFSetField predictor=%d\n", predictor)); 
821         return 0; 
822       }
823     break;
824   case COMPRESSION_PACKBITS:
825     mm_log((1, "i_writetiff_wiol: packbits compression\n"));
826     break;
827   default:
828     mm_log((1, "i_writetiff_wiol: unknown compression %d\n", compression));
829     return 0;
830   }
831   
832   linebytes = channels * width;
833   linebytes = TIFFScanlineSize(tif) > linebytes ? linebytes 
834     : TIFFScanlineSize(tif);
835   /* working space for the scanlines - we go from 8-bit/pixel to 4 */
836   if (photometric == PHOTOMETRIC_PALETTE && bitspersample == 4)
837     linebytes += linebytes + 1;
838   linebuf = (unsigned char *)_TIFFmalloc(linebytes);
839   
840   if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, rowsperstrip))) {
841     mm_log((1, "i_writetiff_wiol: TIFFSetField rowsperstrip=%d\n", rowsperstrip)); return 0; }
842
843   TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
844   TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rc);
845
846   mm_log((1, "i_writetiff_wiol: TIFFGetField rowsperstrip=%d\n", rowsperstrip));
847   mm_log((1, "i_writetiff_wiol: TIFFGetField scanlinesize=%d\n", TIFFScanlineSize(tif) ));
848   mm_log((1, "i_writetiff_wiol: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG));
849   mm_log((1, "i_writetiff_wiol: bitspersample = %d\n", bitspersample));
850
851   got_xres = i_tags_get_float(&im->tags, "i_xres", 0, &xres);
852   got_yres = i_tags_get_float(&im->tags, "i_yres", 0, &yres);
853   if (!i_tags_get_int(&im->tags, "i_aspect_only", 0,&aspect_only))
854     aspect_only = 0;
855   if (!i_tags_get_int(&im->tags, "tiff_resolutionunit", 0, &resunit))
856     resunit = RESUNIT_INCH;
857   if (got_xres || got_yres) {
858     if (!got_xres)
859       xres = yres;
860     else if (!got_yres)
861       yres = xres;
862     if (aspect_only) {
863       resunit = RESUNIT_NONE;
864     }
865     else {
866       if (resunit == RESUNIT_CENTIMETER) {
867         xres /= 2.54;
868         yres /= 2.54;
869       }
870       else {
871         resunit  = RESUNIT_INCH;
872       }
873     }
874     if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)xres)) {
875       i_push_error(0, "cannot set TIFFTAG_XRESOLUTION tag");
876       return 0;
877     }
878     if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)yres)) {
879       i_push_error(0, "cannot set TIFFTAG_YRESOLUTION tag");
880       return 0;
881     }
882     if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (uint16)resunit)) {
883       i_push_error(0, "cannot set TIFFTAG_RESOLUTIONUNIT tag");
884       return 0;
885     }
886   }
887
888   if (!save_tiff_tags(tif, im)) {
889     return 0;
890   }
891
892   if (photometric == PHOTOMETRIC_PALETTE) {
893     for (y = 0; y < height; ++y) {
894       i_gpal(im, 0, width, y, linebuf);
895       if (bitspersample == 4)
896         pack_4bit_hl(linebuf, width);
897       if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
898         mm_log((1, "i_writetiff_wiol: TIFFWriteScanline failed.\n"));
899         if (linebuf) _TIFFfree(linebuf);
900         if (colors) _TIFFfree(colors);
901         return 0;
902       }
903     }
904   }
905   else {
906     for (y=0; y<height; y++) {
907       ci = 0;
908       for(x=0; x<width; x++) { 
909         (void) i_gpix(im, x, y,&val);
910         for(ch=0; ch<channels; ch++) 
911           linebuf[ci++] = val.channel[ch];
912       }
913       if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
914         mm_log((1, "i_writetiff_wiol: TIFFWriteScanline failed.\n"));
915         if (linebuf) _TIFFfree(linebuf);
916         if (colors) _TIFFfree(colors);
917         return 0;
918       }
919     }
920   }
921   if (linebuf) _TIFFfree(linebuf);
922   if (colors) _TIFFfree(colors);
923   return 1;
924 }
925
926 /*
927 =item i_writetiff_multi_wiol(ig, imgs, count, fine_mode)
928
929 Stores an image in the iolayer object.
930
931    ig - io_object that defines source to write to 
932    imgs,count - the images to write
933
934 =cut 
935 */
936
937 undef_int
938 i_writetiff_multi_wiol(io_glue *ig, i_img **imgs, int count) {
939   TIFF* tif;
940   TIFFErrorHandler old_handler;
941   int i;
942
943   old_handler = TIFFSetErrorHandler(error_handler);
944
945   io_glue_commit_types(ig);
946   i_clear_error();
947   mm_log((1, "i_writetiff_multi_wiol(ig 0x%p, imgs 0x%p, count %d)\n", 
948           ig, imgs, count));
949
950   /* FIXME: Enable the mmap interface */
951   
952   tif = TIFFClientOpen("No name", 
953                        "wm",
954                        (thandle_t) ig, 
955                        (TIFFReadWriteProc) ig->readcb,
956                        (TIFFReadWriteProc) ig->writecb,
957                        (TIFFSeekProc)      comp_seek,
958                        (TIFFCloseProc)     ig->closecb, 
959                        ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
960                        (TIFFMapFileProc)   comp_mmap,
961                        (TIFFUnmapFileProc) comp_munmap);
962   
963
964
965   if (!tif) {
966     mm_log((1, "i_writetiff_multi_wiol: Unable to open tif file for writing\n"));
967     i_push_error(0, "Could not create TIFF object");
968     TIFFSetErrorHandler(old_handler);
969     return 0;
970   }
971
972   for (i = 0; i < count; ++i) {
973     if (!i_writetiff_low(tif, imgs[i])) {
974       TIFFClose(tif);
975       TIFFSetErrorHandler(old_handler);
976       return 0;
977     }
978
979     if (!TIFFWriteDirectory(tif)) {
980       i_push_error(0, "Cannot write TIFF directory");
981       TIFFClose(tif);
982       TIFFSetErrorHandler(old_handler);
983       return 0;
984     }
985   }
986
987   TIFFSetErrorHandler(old_handler);
988   (void) TIFFClose(tif);
989
990   return 1;
991 }
992
993 /*
994 =item i_writetiff_multi_wiol_faxable(ig, imgs, count, fine_mode)
995
996 Stores an image in the iolayer object.
997
998    ig - io_object that defines source to write to 
999    imgs,count - the images to write
1000    fine_mode - select fine or normal mode fax images
1001
1002 =cut 
1003 */
1004
1005
1006 undef_int
1007 i_writetiff_multi_wiol_faxable(io_glue *ig, i_img **imgs, int count, int fine) {
1008   TIFF* tif;
1009   int i;
1010   TIFFErrorHandler old_handler;
1011
1012   old_handler = TIFFSetErrorHandler(error_handler);
1013
1014   io_glue_commit_types(ig);
1015   i_clear_error();
1016   mm_log((1, "i_writetiff_multi_wiol(ig 0x%p, imgs 0x%p, count %d)\n", 
1017           ig, imgs, count));
1018
1019   /* FIXME: Enable the mmap interface */
1020   
1021   tif = TIFFClientOpen("No name", 
1022                        "wm",
1023                        (thandle_t) ig, 
1024                        (TIFFReadWriteProc) ig->readcb,
1025                        (TIFFReadWriteProc) ig->writecb,
1026                        (TIFFSeekProc)      comp_seek,
1027                        (TIFFCloseProc)     ig->closecb, 
1028                        ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
1029                        (TIFFMapFileProc)   comp_mmap,
1030                        (TIFFUnmapFileProc) comp_munmap);
1031   
1032
1033
1034   if (!tif) {
1035     mm_log((1, "i_writetiff_mulit_wiol: Unable to open tif file for writing\n"));
1036     i_push_error(0, "Could not create TIFF object");
1037     TIFFSetErrorHandler(old_handler);
1038     return 0;
1039   }
1040
1041   for (i = 0; i < count; ++i) {
1042     if (!i_writetiff_low_faxable(tif, imgs[i], fine)) {
1043       TIFFClose(tif);
1044       TIFFSetErrorHandler(old_handler);
1045       return 0;
1046     }
1047
1048     if (!TIFFWriteDirectory(tif)) {
1049       i_push_error(0, "Cannot write TIFF directory");
1050       TIFFClose(tif);
1051       TIFFSetErrorHandler(old_handler);
1052       return 0;
1053     }
1054   }
1055
1056   (void) TIFFClose(tif);
1057   TIFFSetErrorHandler(old_handler);
1058
1059   return 1;
1060 }
1061
1062 /*
1063 =item i_writetiff_wiol(im, ig)
1064
1065 Stores an image in the iolayer object.
1066
1067    im - image object to write out
1068    ig - io_object that defines source to write to 
1069
1070 =cut 
1071 */
1072 undef_int
1073 i_writetiff_wiol(i_img *img, io_glue *ig) {
1074   TIFF* tif;
1075   TIFFErrorHandler old_handler;
1076
1077   old_handler = TIFFSetErrorHandler(error_handler);
1078
1079   io_glue_commit_types(ig);
1080   i_clear_error();
1081   mm_log((1, "i_writetiff_wiol(img %p, ig 0x%p)\n", img, ig));
1082
1083   /* FIXME: Enable the mmap interface */
1084
1085   tif = TIFFClientOpen("No name", 
1086                        "wm",
1087                        (thandle_t) ig, 
1088                        (TIFFReadWriteProc) ig->readcb,
1089                        (TIFFReadWriteProc) ig->writecb,
1090                        (TIFFSeekProc)      comp_seek,
1091                        (TIFFCloseProc)     ig->closecb, 
1092                        ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
1093                        (TIFFMapFileProc)   comp_mmap,
1094                        (TIFFUnmapFileProc) comp_munmap);
1095   
1096
1097
1098   if (!tif) {
1099     mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
1100     i_push_error(0, "Could not create TIFF object");
1101     TIFFSetErrorHandler(old_handler);
1102     return 0;
1103   }
1104
1105   if (!i_writetiff_low(tif, img)) {
1106     TIFFClose(tif);
1107     TIFFSetErrorHandler(old_handler);
1108     return 0;
1109   }
1110
1111   (void) TIFFClose(tif);
1112   TIFFSetErrorHandler(old_handler);
1113
1114   return 1;
1115 }
1116
1117
1118
1119 /*
1120 =item i_writetiff_wiol_faxable(i_img *, io_glue *)
1121
1122 Stores an image in the iolayer object in faxable tiff format.
1123
1124    im - image object to write out
1125    ig - io_object that defines source to write to 
1126
1127 Note, this may be rewritten to use to simply be a call to a
1128 lower-level function that gives more options for writing tiff at some
1129 point.
1130
1131 =cut
1132 */
1133
1134 undef_int
1135 i_writetiff_wiol_faxable(i_img *im, io_glue *ig, int fine) {
1136   TIFF* tif;
1137   TIFFErrorHandler old_handler;
1138
1139   old_handler = TIFFSetErrorHandler(error_handler);
1140
1141   io_glue_commit_types(ig);
1142   i_clear_error();
1143   mm_log((1, "i_writetiff_wiol(img %p, ig 0x%p)\n", im, ig));
1144
1145   /* FIXME: Enable the mmap interface */
1146   
1147   tif = TIFFClientOpen("No name", 
1148                        "wm",
1149                        (thandle_t) ig, 
1150                        (TIFFReadWriteProc) ig->readcb,
1151                        (TIFFReadWriteProc) ig->writecb,
1152                        (TIFFSeekProc)      comp_seek,
1153                        (TIFFCloseProc)     ig->closecb, 
1154                        ig->sizecb ? (TIFFSizeProc) ig->sizecb : (TIFFSizeProc) sizeproc,
1155                        (TIFFMapFileProc)   comp_mmap,
1156                        (TIFFUnmapFileProc) comp_munmap);
1157   
1158
1159
1160   if (!tif) {
1161     mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
1162     i_push_error(0, "Could not create TIFF object");
1163     TIFFSetErrorHandler(old_handler);
1164     return 0;
1165   }
1166
1167   if (!i_writetiff_low_faxable(tif, im, fine)) {
1168     TIFFClose(tif);
1169     TIFFSetErrorHandler(old_handler);
1170     return 0;
1171   }
1172
1173   (void) TIFFClose(tif);
1174   TIFFSetErrorHandler(old_handler);
1175
1176   return 1;
1177 }
1178
1179 static int save_tiff_tags(TIFF *tif, i_img *im) {
1180   int i;
1181  
1182   for (i = 0; i < text_tag_count; ++i) {
1183     int entry;
1184     if (i_tags_find(&im->tags, text_tag_names[i].name, 0, &entry)) {
1185       if (!TIFFSetField(tif, text_tag_names[i].tag, 
1186                        im->tags.tags[entry].data)) {
1187        i_push_errorf(0, "cannot save %s to TIFF", text_tag_names[i].name);
1188        return 0;
1189       }
1190     }
1191   }
1192  
1193   return 1;
1194 }
1195
1196
1197 /*
1198 =item expand_4bit_hl(buf, count)
1199
1200 Expands 4-bit/entry packed data into 1 byte/entry.
1201
1202 buf must contain count bytes to be expanded and have 2*count bytes total 
1203 space.
1204
1205 The data is expanded in place.
1206
1207 =cut
1208 */
1209
1210 static void expand_4bit_hl(unsigned char *buf, int count) {
1211   while (--count >= 0) {
1212     buf[count*2+1] = buf[count] & 0xF;
1213     buf[count*2] = buf[count] >> 4;
1214   }
1215 }
1216
1217 static void pack_4bit_hl(unsigned char *buf, int count) {
1218   int i = 0;
1219   while (i < count) {
1220     buf[i/2] = (buf[i] << 4) + buf[i+1];
1221     i += 2;
1222   }
1223 }
1224
1225 /*
1226 =back
1227
1228 =head1 AUTHOR
1229
1230 Arnar M. Hrafnkelsson <addi@umich.edu>
1231
1232 =head1 SEE ALSO
1233
1234 Imager(3)
1235
1236 =cut
1237 */