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