Fixed i_transform2() so malloc(0) doesn't happen. Also corrected pod errors and
[imager.git] / tiff.c
1 #include "image.h"
2 #include "tiffio.h"
3 #include "iolayer.h"
4
5 /*
6 =head1 NAME
7
8 tiff.c - implements reading and writing tiff files, uses io layer.
9
10 =head1 SYNOPSIS
11
12    io_glue *ig = io_new_fd( fd );
13    i_img *im   = i_readtiff_wiol(ig, -1); // no limit on how much is read
14    // or 
15    io_glue *ig = io_new_fd( fd );
16    return_code = i_writetiff_wiol(im, ig); 
17
18 =head1 DESCRIPTION
19
20 tiff.c implements the basic functions to read and write tiff files.
21 It uses the iolayer and needs either a seekable source or an entire
22 memory mapped buffer.
23
24 =head1 FUNCTION REFERENCE
25
26 Some of these functions are internal.
27
28 =over
29
30 =cut
31 */
32
33 /*
34 =item comp_seek(h, o, w)
35
36 Compatability for 64 bit systems like latest freebsd (internal)
37
38    h - tiff handle, cast an io_glue object
39    o - offset
40    w - whence
41
42 =cut
43 */
44
45 static
46 toff_t
47 comp_seek(thandle_t h, toff_t o, int w) {
48   io_glue *ig = (io_glue*)h;
49   return (toff_t) ig->seekcb(ig, o, w);
50 }
51
52
53 /*
54 =item i_readtiff_wiol(ig, length)
55
56 Retrieve an image and stores in the iolayer object. Returns NULL on fatal error.
57
58    ig     - io_glue object
59    length - maximum length to read from data source, before closing it
60
61 =cut
62 */
63
64 i_img*
65 i_readtiff_wiol(io_glue *ig, int length) {
66   i_img *im;
67   uint32 width, height;
68   uint16 channels;
69   uint32* raster;
70   int tiled, error;
71   TIFF* tif;
72   float xres, yres;
73   uint16 resunit;
74   int gotXres, gotYres;
75
76   error = 0;
77
78   /* Add code to get the filename info from the iolayer */
79   /* Also add code to check for mmapped code */
80
81   io_glue_commit_types(ig);
82   mm_log((1, "i_readtiff_wiol(ig %p, length %d)\n", ig, length));
83   
84   tif = TIFFClientOpen("Iolayer: FIXME", 
85                        "rm", 
86                        (thandle_t) ig,
87                        (TIFFReadWriteProc) ig->readcb,
88                        (TIFFReadWriteProc) ig->writecb,
89                        (TIFFSeekProc) comp_seek,
90                        (TIFFCloseProc) ig->closecb,
91                        (TIFFSizeProc) ig->sizecb,
92                        (TIFFMapFileProc) NULL,
93                        (TIFFUnmapFileProc) NULL);
94   
95   if (!tif) {
96     mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
97     return NULL;
98   }
99
100   TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
101   TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
102   TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &channels);
103   tiled = TIFFIsTiled(tif);
104
105   mm_log((1, "i_readtiff_wiol: width=%d, height=%d, channels=%d\n", width, height, channels));
106   mm_log((1, "i_readtiff_wiol: %stiled\n", tiled?"":"not "));
107   mm_log((1, "i_readtiff_wiol: %sbyte swapped\n", TIFFIsByteSwapped(tif)?"":"not "));
108   
109   im = i_img_empty_ch(NULL, width, height, channels);
110
111   if (!TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &resunit))
112     resunit = RESUNIT_INCH;
113   gotXres = TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres);
114   gotYres = TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres);
115   if (gotXres || gotYres) {
116     if (!gotXres)
117       xres = yres;
118     else if (!gotYres)
119       yres = xres;
120     if (resunit == RESUNIT_CENTIMETER) {
121       /* from dots per cm to dpi */
122       xres *= 2.54;
123       yres *= 2.54;
124     }
125     i_tags_addn(&im->tags, "tiff_resolutionunit", 0, resunit);
126     if (resunit == RESUNIT_NONE)
127       i_tags_addn(&im->tags, "i_aspect_only", 0, 1);
128     i_tags_set_float(&im->tags, "i_xres", 0, xres);
129     i_tags_set_float(&im->tags, "i_yres", 0, yres);
130   }
131   
132   /*   TIFFPrintDirectory(tif, stdout, 0); good for debugging */
133   
134   if (tiled) {
135     int ok = 1;
136     uint32 row, col;
137     uint32 tile_width, tile_height;
138
139     TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width);
140     TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height);
141     mm_log((1, "i_readtiff_wiol: tile_width=%d, tile_height=%d\n", tile_width, tile_height));
142
143     raster = (uint32*)_TIFFmalloc(tile_width * tile_height * sizeof (uint32));
144     if (!raster) {
145       TIFFError(TIFFFileName(tif), "No space for raster buffer");
146       return NULL;
147     }
148     
149     for( row = 0; row < height; row += tile_height ) {
150       for( col = 0; ok && col < width; col += tile_width ) {
151         uint32 i_row, x, newrows, newcols;
152
153         /* Read the tile into an RGBA array */
154         if (!TIFFReadRGBATile(tif, col, row, raster)) {
155           ok = 0;
156           break;
157         }
158         newrows = (row+tile_height > height) ? height-row : tile_height;
159         mm_log((1, "i_readtiff_wiol: newrows=%d\n", newrows));
160         newcols = (col+tile_width  > width ) ? width-row  : tile_width;
161         for( i_row = 0; i_row < tile_height; i_row++ ) {
162           for(x = 0; x < newcols; x++) {
163             i_color val;               /* FIXME: Make sure this works everywhere */
164             val.ui = raster[x+tile_width*(tile_height-i_row-1)];
165             i_ppix(im, col+x, row+i_row, &val);
166           }
167         }
168       }
169     }
170   } else {
171     uint32 rowsperstrip, row;
172     TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
173     mm_log((1, "i_readtiff_wiol: rowsperstrip=%d\n", rowsperstrip));
174     
175     raster = (uint32*)_TIFFmalloc(width * rowsperstrip * sizeof (uint32));
176     if (!raster) {
177       TIFFError(TIFFFileName(tif), "No space for raster buffer");
178       return NULL;
179     }
180     
181     for( row = 0; row < height; row += rowsperstrip ) {
182       uint32 newrows, i_row;
183       
184       if (!TIFFReadRGBAStrip(tif, row, raster)) {
185         error++;
186         break;
187       }
188       
189       newrows = (row+rowsperstrip > height) ? height-row : rowsperstrip;
190       mm_log((1, "newrows=%d\n", newrows));
191       
192       for( i_row = 0; i_row < newrows; i_row++ ) { 
193         uint32 x;
194         for(x = 0; x<width; x++) {
195           i_color val;               /* FIXME: Make sure this works everywhere */
196           val.ui = raster[x+width*(newrows-i_row-1)];
197           i_ppix(im, x, i_row+row, &val);
198         }
199       }
200     }
201
202   }
203   if (error) {
204     mm_log((1, "i_readtiff_wiol: error during reading\n"));
205   }
206   _TIFFfree( raster );
207   if (TIFFLastDirectory(tif)) mm_log((1, "Last directory of tiff file\n"));
208   return im;
209 }
210
211
212
213 /*
214 =item i_writetif_wiol(im, ig)
215
216 Stores an image in the iolayer object.
217
218    im - image object to write out
219    ig - io_object that defines source to write to 
220
221 =cut 
222 */
223
224
225 /* FIXME: Add an options array in here soonish */
226
227 undef_int
228 i_writetiff_wiol(i_img *im, io_glue *ig) {
229   uint32 width, height;
230   uint16 channels;
231   uint16 predictor = 0;
232   int quality = 75;
233   int jpegcolormode = JPEGCOLORMODE_RGB;
234   uint16 compression = COMPRESSION_PACKBITS;
235   i_color val;
236   uint16 photometric;
237   uint32 rowsperstrip = (uint32) -1;  /* Let library pick default */
238   unsigned char *linebuf = NULL;
239   uint32 y;
240   tsize_t linebytes;
241   int ch, ci, rc;
242   uint32 x;
243   TIFF* tif;
244   int got_xres, got_yres, got_aspectonly, aspect_only, resunit;
245   double xres, yres;
246
247   char *cc = mymalloc( 123 );
248   myfree(cc);
249
250
251   width    = im->xsize;
252   height   = im->ysize;
253   channels = im->channels;
254
255   switch (channels) {
256   case 1:
257     photometric = PHOTOMETRIC_MINISBLACK;
258     break;
259   case 3:
260     photometric = PHOTOMETRIC_RGB;
261     if (compression == COMPRESSION_JPEG && jpegcolormode == JPEGCOLORMODE_RGB) photometric = PHOTOMETRIC_YCBCR;
262     break;
263   default:
264     /* This means a colorspace we don't handle yet */
265     mm_log((1, "i_writetiff_wiol: don't handle %d channel images.\n", channels));
266     return 0;
267   }
268
269   /* Add code to get the filename info from the iolayer */
270   /* Also add code to check for mmapped code */
271
272   io_glue_commit_types(ig);
273   mm_log((1, "i_writetiff_wiol(im 0x%p, ig 0x%p)\n", im, ig));
274
275   /* FIXME: Enable the mmap interface */
276   
277   tif = TIFFClientOpen("No name", 
278                        "wm",
279                        (thandle_t) ig, 
280                        (TIFFReadWriteProc) ig->readcb,
281                        (TIFFReadWriteProc) ig->writecb,
282                        (TIFFSeekProc)      comp_seek,
283                        (TIFFCloseProc)     ig->closecb, 
284                        (TIFFSizeProc)      ig->sizecb,
285                        (TIFFMapFileProc)   NULL,
286                        (TIFFUnmapFileProc) NULL);
287   
288
289
290   if (!tif) {
291     mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
292     return 0;
293   }
294
295   mm_log((1, "i_writetiff_wiol: width=%d, height=%d, channels=%d\n", width, height, channels));
296   
297   if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH,      width)   ) { mm_log((1, "i_writetiff_wiol: TIFFSetField width=%d failed\n", width)); return 0; }
298   if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH,     height)  ) { mm_log((1, "i_writetiff_wiol: TIFFSetField length=%d failed\n", height)); return 0; }
299   if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, channels)) { mm_log((1, "i_writetiff_wiol: TIFFSetField samplesperpixel=%d failed\n", channels)); return 0; }
300   if (!TIFFSetField(tif, TIFFTAG_ORIENTATION,  ORIENTATION_TOPLEFT)) { mm_log((1, "i_writetiff_wiol: TIFFSetField Orientation=topleft\n")); return 0; }
301   if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,   8)        ) { mm_log((1, "i_writetiff_wiol: TIFFSetField bitpersample=8\n")); return 0; }
302   if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) { mm_log((1, "i_writetiff_wiol: TIFFSetField planarconfig\n")); return 0; }
303   if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC,   photometric)) { mm_log((1, "i_writetiff_wiol: TIFFSetField photometric=%d\n", photometric)); return 0; }
304   if (!TIFFSetField(tif, TIFFTAG_COMPRESSION,   compression)) { mm_log((1, "i_writetiff_wiol: TIFFSetField compression=%d\n", compression)); return 0; }
305
306   switch (compression) {
307   case COMPRESSION_JPEG:
308     mm_log((1, "i_writetiff_wiol: jpeg compression\n"));
309     if (!TIFFSetField(tif, TIFFTAG_JPEGQUALITY, quality)        ) { mm_log((1, "i_writetiff_wiol: TIFFSetField jpegquality=%d\n", quality)); return 0; }
310     if (!TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, jpegcolormode)) { mm_log((1, "i_writetiff_wiol: TIFFSetField jpegcolormode=%d\n", jpegcolormode)); return 0; }
311     break;
312   case COMPRESSION_LZW:
313     mm_log((1, "i_writetiff_wiol: lzw compression\n"));
314     break;
315   case COMPRESSION_DEFLATE:
316     mm_log((1, "i_writetiff_wiol: deflate compression\n"));
317     if (predictor != 0) 
318       if (!TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor)) { mm_log((1, "i_writetiff_wiol: TIFFSetField predictor=%d\n", predictor)); return 0; }
319     break;
320   case COMPRESSION_PACKBITS:
321     mm_log((1, "i_writetiff_wiol: packbits compression\n"));
322     break;
323   default:
324     mm_log((1, "i_writetiff_wiol: unknown compression %d\n", compression));
325     return 0;
326   }
327   
328   linebytes = channels * width;
329   linebuf = (unsigned char *)_TIFFmalloc( TIFFScanlineSize(tif) > linebytes ?
330                                           linebytes : TIFFScanlineSize(tif) );
331   
332   if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, rowsperstrip))) {
333     mm_log((1, "i_writetiff_wiol: TIFFSetField rowsperstrip=%d\n", rowsperstrip)); return 0; }
334
335   TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
336   TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rc);
337
338   mm_log((1, "i_writetiff_wiol: TIFFGetField rowsperstrip=%d\n", rowsperstrip));
339   mm_log((1, "i_writetiff_wiol: TIFFGetField scanlinesize=%d\n", TIFFScanlineSize(tif) ));
340   mm_log((1, "i_writetiff_wiol: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG));
341
342   got_xres = i_tags_get_float(&im->tags, "i_xres", 0, &xres);
343   got_yres = i_tags_get_float(&im->tags, "i_yres", 0, &yres);
344   if (!i_tags_get_int(&im->tags, "i_aspect_only", 0,&aspect_only))
345     aspect_only = 0;
346   if (!i_tags_get_int(&im->tags, "tiff_resolutionunit", 0, &resunit))
347     resunit = RESUNIT_INCH;
348   if (got_xres || got_yres) {
349     if (!got_xres)
350       xres = yres;
351     else if (!got_yres)
352       yres = xres;
353     if (aspect_only) {
354       resunit = RESUNIT_NONE;
355     }
356     else {
357       if (resunit == RESUNIT_CENTIMETER) {
358         xres /= 2.54;
359         yres /= 2.54;
360       }
361       else {
362         resunit  = RESUNIT_INCH;
363       }
364     }
365     if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)xres)) {
366       TIFFClose(tif);
367       i_img_destroy(im);
368       i_push_error(0, "cannot set TIFFTAG_XRESOLUTION tag");
369       return 0;
370     }
371     if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)yres)) {
372       TIFFClose(tif);
373       i_img_destroy(im);
374       i_push_error(0, "cannot set TIFFTAG_YRESOLUTION tag");
375       return 0;
376     }
377     if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, (uint16)resunit)) {
378       TIFFClose(tif);
379       i_img_destroy(im);
380       i_push_error(0, "cannot set TIFFTAG_RESOLUTIONUNIT tag");
381       return 0;
382     }
383   }
384   
385   for (y=0; y<height; y++) {
386     ci = 0;
387     for(x=0; x<width; x++) { 
388       (void) i_gpix(im, x, y,&val);
389       for(ch=0; ch<channels; ch++) linebuf[ci++] = val.channel[ch];
390     }
391     if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
392       mm_log((1, "i_writetiff_wiol: TIFFWriteScanline failed.\n"));
393       break;
394     }
395   }
396   (void) TIFFClose(tif);
397   if (linebuf) _TIFFfree(linebuf);
398   return 1;
399 }
400
401 /*
402 =item i_writetiff_wiol_faxable(i_img *, io_glue *)
403
404 Stores an image in the iolayer object in faxable tiff format.
405
406    im - image object to write out
407    ig - io_object that defines source to write to 
408
409 Note, this may be rewritten to use to simply be a call to a
410 lower-level function that gives more options for writing tiff at some
411 point.
412
413 =cut
414 */
415
416 undef_int
417 i_writetiff_wiol_faxable(i_img *im, io_glue *ig, int fine) {
418   uint32 width, height;
419   unsigned char *linebuf = NULL;
420   uint32 y;
421   int rc;
422   uint32 x;
423   TIFF* tif;
424   int luma_mask;
425   uint32 rowsperstrip;
426   float vres = fine ? 196 : 98;
427   int luma_chan;
428
429   width    = im->xsize;
430   height   = im->ysize;
431
432   switch (im->channels) {
433   case 1:
434   case 2:
435     luma_chan = 0;
436     break;
437   case 3:
438   case 4:
439     luma_chan = 1;
440     break;
441   default:
442     /* This means a colorspace we don't handle yet */
443     mm_log((1, "i_writetiff_wiol_faxable: don't handle %d channel images.\n", im->channels));
444     return 0;
445   }
446
447   /* Add code to get the filename info from the iolayer */
448   /* Also add code to check for mmapped code */
449
450   io_glue_commit_types(ig);
451   mm_log((1, "i_writetiff_wiol_faxable(im 0x%p, ig 0x%p)\n", im, ig));
452
453   /* FIXME: Enable the mmap interface */
454   
455   tif = TIFFClientOpen("No name", 
456                        "wm",
457                        (thandle_t) ig, 
458                        (TIFFReadWriteProc) ig->readcb,
459                        (TIFFReadWriteProc) ig->writecb,
460                        (TIFFSeekProc)      comp_seek,
461                        (TIFFCloseProc)     ig->closecb, 
462                        (TIFFSizeProc)      ig->sizecb,
463                        (TIFFMapFileProc)   NULL,
464                        (TIFFUnmapFileProc) NULL);
465
466   if (!tif) {
467     mm_log((1, "i_writetiff_wiol_faxable: Unable to open tif file for writing\n"));
468     return 0;
469   }
470
471   mm_log((1, "i_writetiff_wiol_faxable: width=%d, height=%d, channels=%d\n", width, height, im->channels));
472   
473   if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH,      width)   )
474     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField width=%d failed\n", width)); return 0; }
475   if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH,     height)  )
476     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField length=%d failed\n", height)); return 0; }
477   if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1))
478     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField samplesperpixel=1 failed\n")); return 0; }
479   if (!TIFFSetField(tif, TIFFTAG_ORIENTATION,  ORIENTATION_TOPLEFT))
480     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Orientation=topleft\n")); return 0; }
481   if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,   1)        )
482     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField bitpersample=1\n")); return 0; }
483   if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG))
484     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField planarconfig\n")); return 0; }
485   if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK))
486     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField photometric=%d\n", PHOTOMETRIC_MINISBLACK)); return 0; }
487   if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, 3))
488     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField compression=3\n")); return 0; }
489
490   linebuf = (unsigned char *)_TIFFmalloc( TIFFScanlineSize(tif) );
491   
492   if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, -1))) {
493     mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField rowsperstrip=-1\n")); return 0; }
494
495   TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
496   TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rc);
497
498   mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField rowsperstrip=%d\n", rowsperstrip));
499   mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField scanlinesize=%d\n", TIFFScanlineSize(tif) ));
500   mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG));
501
502   if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)204))
503     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Xresolution=204\n")); return 0; }
504   if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, vres))
505     { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Yresolution=196\n")); return 0; }
506   if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH)) {
507     mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField ResolutionUnit=%d\n", RESUNIT_INCH)); return 0; 
508   }
509
510   for (y=0; y<height; y++) {
511     int linebufpos=0;
512     for(x=0; x<width; x+=8) { 
513       int bits;
514       int bitpos;
515       i_sample_t luma[8];
516       uint8 bitval = 128;
517       linebuf[linebufpos]=0;
518       bits = width-x; if(bits>8) bits=8;
519       i_gsamp(im, x, x+8, y, luma, &luma_chan, 1);
520       for(bitpos=0;bitpos<bits;bitpos++) {
521         linebuf[linebufpos] |= ((luma[bitpos]>=128)?bitval:0);
522         bitval >>= 1;
523       }
524       linebufpos++;
525     }
526     if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
527       mm_log((1, "i_writetiff_wiol_faxable: TIFFWriteScanline failed.\n"));
528       break;
529     }
530   }
531   (void) TIFFClose(tif);
532   if (linebuf) _TIFFfree(linebuf);
533   return 1;
534 }
535
536
537 /*
538 =back
539
540 =head1 AUTHOR
541
542 Arnar M. Hrafnkelsson <addi@umich.edu>
543
544 =head1 SEE ALSO
545
546 Imager(3)
547
548 =cut
549 */