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