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