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