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