10 tiff.c - implements reading and writing tiff files, uses io layer.
14 io_glue *ig = io_new_fd( fd );
15 i_img *im = i_readtiff_wiol(ig, -1); // no limit on how much is read
17 io_glue *ig = io_new_fd( fd );
18 return_code = i_writetiff_wiol(im, ig);
22 tiff.c implements the basic functions to read and write tiff files.
23 It uses the iolayer and needs either a seekable source or an entire
26 =head1 FUNCTION REFERENCE
28 Some of these functions are internal.
40 =item comp_seek(h, o, w)
42 Compatability for 64 bit systems like latest freebsd (internal)
44 h - tiff handle, cast an io_glue object
53 comp_seek(thandle_t h, toff_t o, int w) {
54 io_glue *ig = (io_glue*)h;
55 return (toff_t) ig->seekcb(ig, o, w);
60 =item i_readtiff_wiol(ig, length)
62 Retrieve an image and stores in the iolayer object. Returns NULL on fatal error.
65 length - maximum length to read from data source, before closing it
71 i_readtiff_wiol(io_glue *ig, int length) {
81 /* Add code to get the filename info from the iolayer */
82 /* Also add code to check for mmapped code */
84 io_glue_commit_types(ig);
85 mm_log((1, "i_readtiff_wiol(ig 0x%p, length %d)\n", ig, length));
87 tif = TIFFClientOpen("Iolayer: FIXME",
90 (TIFFReadWriteProc) ig->readcb,
91 (TIFFReadWriteProc) ig->writecb,
92 (TIFFSeekProc) comp_seek,
93 (TIFFCloseProc) ig->closecb,
94 (TIFFSizeProc) ig->sizecb,
95 (TIFFMapFileProc) NULL,
96 (TIFFUnmapFileProc) NULL);
99 mm_log((1, "i_readtiff_wiol: Unable to open tif file\n"));
103 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
104 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
105 TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &channels);
106 tiled = TIFFIsTiled(tif);
108 mm_log((1, "i_readtiff_wiol: width=%d, height=%d, channels=%d\n", width, height, channels));
109 mm_log((1, "i_readtiff_wiol: %stiled\n", tiled?"":"not "));
110 mm_log((1, "i_readtiff_wiol: %sbyte swapped\n", TIFFIsByteSwapped(tif)?"":"not "));
112 im = i_img_empty_ch(NULL, width, height, channels);
114 /* TIFFPrintDirectory(tif, stdout, 0); good for debugging */
119 uint32 tile_width, tile_height;
121 TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width);
122 TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height);
123 mm_log((1, "i_readtiff_wiol: tile_width=%d, tile_height=%d\n", tile_width, tile_height));
125 raster = (uint32*)_TIFFmalloc(tile_width * tile_height * sizeof (uint32));
127 TIFFError(TIFFFileName(tif), "No space for raster buffer");
131 for( row = 0; row < height; row += tile_height ) {
132 for( col = 0; ok && col < width; col += tile_width ) {
133 uint32 i_row, x, newrows, newcols;
135 /* Read the tile into an RGBA array */
136 if (!TIFFReadRGBATile(tif, col, row, raster)) {
140 newrows = (row+tile_height > height) ? height-row : tile_height;
141 mm_log((1, "i_readtiff_wiol: newrows=%d\n", newrows));
142 newcols = (col+tile_width > width ) ? width-row : tile_width;
143 for( i_row = 0; i_row < tile_height; i_row++ ) {
144 for(x = 0; x < newcols; x++) {
145 i_color val; /* FIXME: Make sure this works everywhere */
146 val.ui = raster[x+tile_width*(tile_height-i_row-1)];
147 i_ppix(im, col+x, row+i_row, &val);
153 uint32 rowsperstrip, row;
154 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
155 mm_log((1, "i_readtiff_wiol: rowsperstrip=%d\n", rowsperstrip));
157 raster = (uint32*)_TIFFmalloc(width * rowsperstrip * sizeof (uint32));
159 TIFFError(TIFFFileName(tif), "No space for raster buffer");
163 for( row = 0; row < height; row += rowsperstrip ) {
164 uint32 newrows, i_row;
166 if (!TIFFReadRGBAStrip(tif, row, raster)) {
171 newrows = (row+rowsperstrip > height) ? height-row : rowsperstrip;
172 mm_log((1, "newrows=%d\n", newrows));
174 for( i_row = 0; i_row < newrows; i_row++ ) {
176 for(x = 0; x<width; x++) {
177 i_color val; /* FIXME: Make sure this works everywhere */
178 val.ui = raster[x+width*(newrows-i_row-1)];
179 i_ppix(im, x, i_row+row, &val);
186 mm_log((1, "i_readtiff_wiol: error during reading\n"));
189 if (TIFFLastDirectory(tif)) mm_log((1, "Last directory of tiff file\n"));
196 =item i_writetif_wiol(im, ig)
198 Stores an image in the iolayer object.
200 im - image object to write out
201 ig - io_object that defines source to write to
207 /* FIXME: Add an options array in here soonish */
210 i_writetiff_wiol(i_img *im, io_glue *ig) {
211 uint32 width, height;
213 uint16 predictor = 0;
215 int jpegcolormode = JPEGCOLORMODE_RGB;
216 uint16 compression = COMPRESSION_PACKBITS;
219 uint32 rowsperstrip = (uint32) -1; /* Let library pick default */
220 double resolution = -1;
221 unsigned char *linebuf = NULL;
228 char *cc = mymalloc( 123 );
234 channels = im->channels;
238 photometric = PHOTOMETRIC_MINISBLACK;
241 photometric = PHOTOMETRIC_RGB;
242 if (compression == COMPRESSION_JPEG && jpegcolormode == JPEGCOLORMODE_RGB) photometric = PHOTOMETRIC_YCBCR;
245 /* This means a colorspace we don't handle yet */
246 mm_log((1, "i_writetiff_wiol: don't handle %d channel images.\n", channels));
250 /* Add code to get the filename info from the iolayer */
251 /* Also add code to check for mmapped code */
253 io_glue_commit_types(ig);
254 mm_log((1, "i_writetiff_wiol(im 0x%p, ig 0x%p)\n", im, ig));
256 /* FIXME: Enable the mmap interface */
258 tif = TIFFClientOpen("No name",
261 (TIFFReadWriteProc) ig->readcb,
262 (TIFFReadWriteProc) ig->writecb,
263 (TIFFSeekProc) comp_seek,
264 (TIFFCloseProc) ig->closecb,
265 (TIFFSizeProc) ig->sizecb,
266 (TIFFMapFileProc) NULL,
267 (TIFFUnmapFileProc) NULL);
272 mm_log((1, "i_writetiff_wiol: Unable to open tif file for writing\n"));
276 mm_log((1, "i_writetiff_wiol: width=%d, height=%d, channels=%d\n", width, height, channels));
278 if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width) ) { mm_log((1, "i_writetiff_wiol: TIFFSetField width=%d failed\n", width)); return 0; }
279 if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height) ) { mm_log((1, "i_writetiff_wiol: TIFFSetField length=%d failed\n", height)); return 0; }
280 if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, channels)) { mm_log((1, "i_writetiff_wiol: TIFFSetField samplesperpixel=%d failed\n", channels)); return 0; }
281 if (!TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT)) { mm_log((1, "i_writetiff_wiol: TIFFSetField Orientation=topleft\n")); return 0; }
282 if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8) ) { mm_log((1, "i_writetiff_wiol: TIFFSetField bitpersample=8\n")); return 0; }
283 if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG)) { mm_log((1, "i_writetiff_wiol: TIFFSetField planarconfig\n")); return 0; }
284 if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric)) { mm_log((1, "i_writetiff_wiol: TIFFSetField photometric=%d\n", photometric)); return 0; }
285 if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, compression)) { mm_log((1, "i_writetiff_wiol: TIFFSetField compression=%d\n", compression)); return 0; }
287 switch (compression) {
288 case COMPRESSION_JPEG:
289 mm_log((1, "i_writetiff_wiol: jpeg compression\n"));
290 if (!TIFFSetField(tif, TIFFTAG_JPEGQUALITY, quality) ) { mm_log((1, "i_writetiff_wiol: TIFFSetField jpegquality=%d\n", quality)); return 0; }
291 if (!TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, jpegcolormode)) { mm_log((1, "i_writetiff_wiol: TIFFSetField jpegcolormode=%d\n", jpegcolormode)); return 0; }
293 case COMPRESSION_LZW:
294 mm_log((1, "i_writetiff_wiol: lzw compression\n"));
296 case COMPRESSION_DEFLATE:
297 mm_log((1, "i_writetiff_wiol: deflate compression\n"));
299 if (!TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor)) { mm_log((1, "i_writetiff_wiol: TIFFSetField predictor=%d\n", predictor)); return 0; }
301 case COMPRESSION_PACKBITS:
302 mm_log((1, "i_writetiff_wiol: packbits compression\n"));
305 mm_log((1, "i_writetiff_wiol: unknown compression %d\n", compression));
309 linebytes = channels * width;
310 linebuf = (unsigned char *)_TIFFmalloc( TIFFScanlineSize(tif) > linebytes ?
311 linebytes : TIFFScanlineSize(tif) );
313 if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, rowsperstrip))) {
314 mm_log((1, "i_writetiff_wiol: TIFFSetField rowsperstrip=%d\n", rowsperstrip)); return 0; }
316 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
317 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rc);
319 mm_log((1, "i_writetiff_wiol: TIFFGetField rowsperstrip=%d\n", rowsperstrip));
320 mm_log((1, "i_writetiff_wiol: TIFFGetField scanlinesize=%d\n", TIFFScanlineSize(tif) ));
321 mm_log((1, "i_writetiff_wiol: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG));
323 if (resolution > 0) {
324 if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, resolution)) { mm_log((1, "i_writetiff_wiol: TIFFSetField Xresolution=%d\n", resolution)); return 0; }
325 if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, resolution)) { mm_log((1, "i_writetiff_wiol: TIFFSetField Yresolution=%d\n", resolution)); return 0; }
326 if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH)) {
327 mm_log((1, "i_writetiff_wiol: TIFFSetField ResolutionUnit=%d\n", RESUNIT_INCH)); return 0;
331 for (y=0; y<height; y++) {
333 for(x=0; x<width; x++) {
334 (void) i_gpix(im, x, y,&val);
335 for(ch=0; ch<channels; ch++) linebuf[ci++] = val.channel[ch];
337 if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
338 mm_log((1, "i_writetiff_wiol: TIFFWriteScanline failed.\n"));
342 (void) TIFFClose(tif);
343 if (linebuf) _TIFFfree(linebuf);
348 =item i_writetiff_wiol_faxable(i_img *, io_glue *)
350 Stores an image in the iolayer object in faxable tiff format.
352 im - image object to write out
353 ig - io_object that defines source to write to
355 Note, this may be rewritten to use to simply be a call to a
356 lower-level function that gives more options for writing tiff at some
363 i_writetiff_wiol_faxable(i_img *im, io_glue *ig, int fine) {
364 uint32 width, height;
365 unsigned char *linebuf = NULL;
372 float vres = fine ? 196 : 98;
377 switch (im->channels) {
385 /* This means a colorspace we don't handle yet */
386 mm_log((1, "i_writetiff_wiol_faxable: don't handle %d channel images.\n", im->channels));
390 /* Add code to get the filename info from the iolayer */
391 /* Also add code to check for mmapped code */
393 io_glue_commit_types(ig);
394 mm_log((1, "i_writetiff_wiol_faxable(im 0x%p, ig 0x%p)\n", im, ig));
396 /* FIXME: Enable the mmap interface */
398 tif = TIFFClientOpen("No name",
401 (TIFFReadWriteProc) ig->readcb,
402 (TIFFReadWriteProc) ig->writecb,
403 (TIFFSeekProc) comp_seek,
404 (TIFFCloseProc) ig->closecb,
405 (TIFFSizeProc) ig->sizecb,
406 (TIFFMapFileProc) NULL,
407 (TIFFUnmapFileProc) NULL);
410 mm_log((1, "i_writetiff_wiol_faxable: Unable to open tif file for writing\n"));
414 mm_log((1, "i_writetiff_wiol_faxable: width=%d, height=%d, channels=%d\n", width, height, im->channels));
416 if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width) )
417 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField width=%d failed\n", width)); return 0; }
418 if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height) )
419 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField length=%d failed\n", height)); return 0; }
420 if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1))
421 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField samplesperpixel=1 failed\n")); return 0; }
422 if (!TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT))
423 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Orientation=topleft\n")); return 0; }
424 if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 1) )
425 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField bitpersample=1\n")); return 0; }
426 if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG))
427 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField planarconfig\n")); return 0; }
428 if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK))
429 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField photometric=%d\n", PHOTOMETRIC_MINISBLACK)); return 0; }
430 if (!TIFFSetField(tif, TIFFTAG_COMPRESSION, 3))
431 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField compression=3\n")); return 0; }
433 linebuf = (unsigned char *)_TIFFmalloc( TIFFScanlineSize(tif) );
435 if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, -1))) {
436 mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField rowsperstrip=-1\n")); return 0; }
438 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
439 TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rc);
441 mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField rowsperstrip=%d\n", rowsperstrip));
442 mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField scanlinesize=%d\n", TIFFScanlineSize(tif) ));
443 mm_log((1, "i_writetiff_wiol_faxable: TIFFGetField planarconfig=%d == %d\n", rc, PLANARCONFIG_CONTIG));
445 if (!TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)204))
446 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Xresolution=204\n")); return 0; }
447 if (!TIFFSetField(tif, TIFFTAG_YRESOLUTION, vres))
448 { mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField Yresolution=196\n")); return 0; }
449 if (!TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH)) {
450 mm_log((1, "i_writetiff_wiol_faxable: TIFFSetField ResolutionUnit=%d\n", RESUNIT_INCH)); return 0;
453 for (y=0; y<height; y++) {
455 for(x=0; x<width; x+=8) {
459 linebuf[linebufpos]=0;
460 bits = width-x; if(bits>8) bits=8;
461 for(bitpos=0;bitpos<bits;bitpos++) {
463 luma = im->data[(x+bitpos+y*im->xsize)*im->channels+luma_channel];
464 linebuf[linebufpos] |= ((luma>=128)?bitval:0);
469 if (TIFFWriteScanline(tif, linebuf, y, 0) < 0) {
470 mm_log((1, "i_writetiff_wiol_faxable: TIFFWriteScanline failed.\n"));
474 (void) TIFFClose(tif);
475 if (linebuf) _TIFFfree(linebuf);