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