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