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