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