1 /* $Header: /cvs/maptools/cvsroot/libtiff/contrib/pds/tif_imageiter.c,v 1.4 2010-06-08 18:55:15 bfriesen Exp $ */
4 * Copyright (c) 1991-1996 Sam Leffler
5 * Copyright (c) 1991-1996 Silicon Graphics, Inc.
7 * Permission to use, copy, modify, distribute, and sell this software and
8 * its documentation for any purpose is hereby granted without fee, provided
9 * that (i) the above copyright notices and this permission notice appear in
10 * all copies of the software and related documentation, and (ii) the names of
11 * Sam Leffler and Silicon Graphics may not be used in any advertising or
12 * publicity relating to the software without the specific, prior written
13 * permission of Sam Leffler and Silicon Graphics.
15 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
17 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
19 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
20 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
21 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
23 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
30 * Written by Conrad J. Poelman, PL/WSAT, Kirtland AFB, NM on 26 Mar 96.
32 * This file contains code to allow a calling program to "iterate" over each
33 * pixels in an image as it is read from the file. The iterator takes care of
34 * reading strips versus (possibly clipped) tiles, decoding the information
35 * according to the decoding method, and so on, so that calling program can
36 * ignore those details. The calling program does, however, need to be
37 * conscious of the type of the pixel data that it is receiving.
39 * For reasons of efficiency, the callback function actually gets called for
40 * "blocks" of pixels rather than for individual pixels. The format of the
41 * callback arguments is given below.
43 * This code was taken from TIFFReadRGBAImage() in tif_getimage.c of the original
44 * TIFF distribution, and simplified and generalized to provide this general
45 * iteration capability. Those routines could certainly be re-implemented in terms
46 * of a TIFFImageIter if desired.
50 #include "tif_imageiter.h"
54 static int gtTileContig(TIFFImageIter*, void *udata, uint32, uint32);
55 static int gtTileSeparate(TIFFImageIter*, void *udata, uint32, uint32);
56 static int gtStripContig(TIFFImageIter*, void *udata, uint32, uint32);
57 static int gtStripSeparate(TIFFImageIter*, void *udata, uint32, uint32);
59 static const char photoTag[] = "PhotometricInterpretation";
62 isCCITTCompression(TIFF* tif)
65 TIFFGetField(tif, TIFFTAG_COMPRESSION, &compress);
66 return (compress == COMPRESSION_CCITTFAX3 ||
67 compress == COMPRESSION_CCITTFAX4 ||
68 compress == COMPRESSION_CCITTRLE ||
69 compress == COMPRESSION_CCITTRLEW);
73 TIFFImageIterBegin(TIFFImageIter* img, TIFF* tif, int stop, char emsg[1024])
81 img->stoponerr = stop;
82 TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &img->bitspersample);
84 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &img->samplesperpixel);
85 TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES,
86 &extrasamples, &sampleinfo);
87 if (extrasamples == 1)
88 switch (sampleinfo[0]) {
89 case EXTRASAMPLE_ASSOCALPHA: /* data is pre-multiplied */
90 case EXTRASAMPLE_UNASSALPHA: /* data is not pre-multiplied */
91 img->alpha = sampleinfo[0];
94 colorchannels = img->samplesperpixel - extrasamples;
95 TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig);
96 if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) {
97 switch (colorchannels) {
99 if (isCCITTCompression(tif))
100 img->photometric = PHOTOMETRIC_MINISWHITE;
102 img->photometric = PHOTOMETRIC_MINISBLACK;
105 img->photometric = PHOTOMETRIC_RGB;
108 sprintf(emsg, "Missing needed %s tag", photoTag);
112 switch (img->photometric) {
113 case PHOTOMETRIC_PALETTE:
114 if (!TIFFGetField(tif, TIFFTAG_COLORMAP,
115 &img->redcmap, &img->greencmap, &img->bluecmap)) {
116 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "Missing required \"Colormap\" tag");
120 case PHOTOMETRIC_MINISWHITE:
121 case PHOTOMETRIC_MINISBLACK:
122 /* This should work now so skip the check - BSR
123 if (planarconfig == PLANARCONFIG_CONTIG && img->samplesperpixel != 1) {
125 "Sorry, can not handle contiguous data with %s=%d, and %s=%d",
126 photoTag, img->photometric,
127 "Samples/pixel", img->samplesperpixel);
132 case PHOTOMETRIC_YCBCR:
133 if (planarconfig != PLANARCONFIG_CONTIG) {
134 sprintf(emsg, "Sorry, can not handle YCbCr images with %s=%d",
135 "Planarconfiguration", planarconfig);
138 /* It would probably be nice to have a reality check here. */
140 TIFFGetField(tif, TIFFTAG_COMPRESSION, &compress);
141 if (compress == COMPRESSION_JPEG && planarconfig == PLANARCONFIG_CONTIG) {
142 /* can rely on libjpeg to convert to RGB */
143 /* XXX should restore current state on exit */
144 TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
145 img->photometric = PHOTOMETRIC_RGB;
149 case PHOTOMETRIC_RGB:
150 if (colorchannels < 3) {
151 sprintf(emsg, "Sorry, can not handle RGB image with %s=%d",
152 "Color channels", colorchannels);
156 case PHOTOMETRIC_SEPARATED: {
158 TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset);
159 if (inkset != INKSET_CMYK) {
160 sprintf(emsg, "Sorry, can not handle separated image with %s=%d",
164 if (img->samplesperpixel != 4) {
165 sprintf(emsg, "Sorry, can not handle separated image with %s=%d",
166 "Samples/pixel", img->samplesperpixel);
172 sprintf(emsg, "Sorry, can not handle image with %s=%d",
173 photoTag, img->photometric);
176 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &img->width);
177 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &img->height);
179 TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &img->orientation);
180 switch (img->orientation) {
181 case ORIENTATION_BOTRIGHT:
182 case ORIENTATION_RIGHTBOT: /* XXX */
183 case ORIENTATION_LEFTBOT: /* XXX */
184 TIFFWarning(TIFFFileName(tif), "using bottom-left orientation");
185 img->orientation = ORIENTATION_BOTLEFT;
187 case ORIENTATION_BOTLEFT:
189 case ORIENTATION_TOPRIGHT:
190 case ORIENTATION_RIGHTTOP: /* XXX */
191 case ORIENTATION_LEFTTOP: /* XXX */
193 TIFFWarning(TIFFFileName(tif), "using top-left orientation");
194 img->orientation = ORIENTATION_TOPLEFT;
196 case ORIENTATION_TOPLEFT:
201 !(planarconfig == PLANARCONFIG_SEPARATE && colorchannels > 1);
203 img->get = TIFFIsTiled(tif) ? gtTileContig : gtStripContig;
205 img->get = TIFFIsTiled(tif) ? gtTileSeparate : gtStripSeparate;
211 TIFFImageIterGet(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
213 if (img->get == NULL) {
214 TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No \"get\" routine setup");
217 if (img->callback.any == NULL) {
218 TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif),
219 "No \"put\" routine setupl; probably can not handle image format");
222 return (*img->get)(img, udata, w, h);
225 TIFFImageIterEnd(TIFFImageIter* img)
227 /* Nothing to free... ? */
231 * Read the specified image into an ABGR-format raster.
234 TIFFReadImageIter(TIFF* tif,
235 uint32 rwidth, uint32 rheight, uint8* raster, int stop)
241 if (TIFFImageIterBegin(&img, tif, stop, emsg)) {
242 /* XXX verify rwidth and rheight against width and height */
243 ok = TIFFImageIterGet(&img, raster, rwidth, img.height);
244 TIFFImageIterEnd(&img);
246 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), emsg);
254 * Get an tile-organized image that has
255 * PlanarConfiguration contiguous if SamplesPerPixel > 1
257 * SamplesPerPixel == 1
260 gtTileContig(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
262 TIFF* tif = img->tif;
263 ImageIterTileContigRoutine callback = img->callback.contig;
271 buf = (u_char*) _TIFFmalloc(TIFFTileSize(tif));
273 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer");
276 TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
277 TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
278 orientation = img->orientation;
279 for (row = 0; row < h; row += th) {
280 nrow = (row + th > h ? h - row : th);
281 for (col = 0; col < w; col += tw) {
282 if (TIFFReadTile(tif, buf, col, row, 0, 0) < 0 && img->stoponerr)
286 * Tile is clipped horizontally. Calculate
287 * visible portion and skewing factors.
289 uint32 npix = w - col;
290 fromskew = tw - npix;
291 (*callback)(img, udata, col, row, npix, nrow, fromskew, buf);
293 (*callback)(img, udata, col, row, tw, nrow, 0, buf);
302 * Get an tile-organized image that has
303 * SamplesPerPixel > 1
304 * PlanarConfiguration separated
305 * We assume that all such images are RGB.
308 gtTileSeparate(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
310 TIFF* tif = img->tif;
311 ImageIterTileSeparateRoutine callback = img->callback.separate;
322 int alpha = img->alpha;
325 tilesize = TIFFTileSize(tif);
326 buf = (u_char*) _TIFFmalloc(4*tilesize);
328 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer");
336 memset(a, 0xff, tilesize);
337 TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw);
338 TIFFGetField(tif, TIFFTAG_TILELENGTH, &th);
339 orientation = img->orientation;
340 for (row = 0; row < h; row += th) {
341 nrow = (row + th > h ? h - row : th);
342 for (col = 0; col < w; col += tw) {
343 if (TIFFReadTile(tif, r, col, row,0,0) < 0 && img->stoponerr)
345 if (TIFFReadTile(tif, g, col, row,0,1) < 0 && img->stoponerr)
347 if (TIFFReadTile(tif, b, col, row,0,2) < 0 && img->stoponerr)
349 if (alpha && TIFFReadTile(tif,a,col,row,0,3) < 0 && img->stoponerr)
353 * Tile is clipped horizontally. Calculate
354 * visible portion and skewing factors.
356 uint32 npix = w - col;
357 fromskew = tw - npix;
358 (*callback)(img, udata, col, row, npix, nrow, fromskew, r, g, b, a);
360 (*callback)(img, udata, col, row, tw, nrow, 0, r, g, b, a);
369 * Get a strip-organized image that has
370 * PlanarConfiguration contiguous if SamplesPerPixel > 1
372 * SamplesPerPixel == 1
375 gtStripContig(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
377 TIFF* tif = img->tif;
378 ImageIterTileContigRoutine callback = img->callback.contig;
383 uint32 imagewidth = img->width;
387 buf = (u_char*) _TIFFmalloc(TIFFStripSize(tif));
389 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for strip buffer");
392 orientation = img->orientation;
393 TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
394 scanline = TIFFScanlineSize(tif);
395 fromskew = (w < imagewidth ? imagewidth - w : 0);
396 for (row = 0; row < h; row += rowsperstrip) {
397 nrow = (row + rowsperstrip > h ? h - row : rowsperstrip);
398 if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 0),
399 buf, nrow*scanline) < 0 && img->stoponerr)
401 (*callback)(img, udata, 0, row, w, nrow, fromskew, buf);
408 * Get a strip-organized image with
409 * SamplesPerPixel > 1
410 * PlanarConfiguration separated
411 * We assume that all such images are RGB.
414 gtStripSeparate(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
416 TIFF* tif = img->tif;
417 ImageIterTileSeparateRoutine callback = img->callback.separate;
420 u_char *r, *g, *b, *a;
424 uint32 imagewidth = img->width;
427 int alpha = img->alpha;
429 stripsize = TIFFStripSize(tif);
430 r = buf = (u_char *)_TIFFmalloc(4*stripsize);
432 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer");
439 memset(a, 0xff, stripsize);
440 orientation = img->orientation;
441 TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip);
442 scanline = TIFFScanlineSize(tif);
443 fromskew = (w < imagewidth ? imagewidth - w : 0);
444 for (row = 0; row < h; row += rowsperstrip) {
445 nrow = (row + rowsperstrip > h ? h - row : rowsperstrip);
446 if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 0),
447 r, nrow*scanline) < 0 && img->stoponerr)
449 if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 1),
450 g, nrow*scanline) < 0 && img->stoponerr)
452 if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 2),
453 b, nrow*scanline) < 0 && img->stoponerr)
456 (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 3),
457 a, nrow*scanline) < 0 && img->stoponerr))
459 (*callback)(img, udata, 0, row, w, nrow, fromskew, r, g, b, a);
465 DECLAREContigCallbackFunc(TestContigCallback)
467 printf("Contig Callback called with x = %d, y = %d, w = %d, h = %d, fromskew = %d\n",
468 x, y, w, h, fromskew);
472 DECLARESepCallbackFunc(TestSepCallback)
474 printf("Sep Callback called with x = %d, y = %d, w = %d, h = %d, fromskew = %d\n",
475 x, y, w, h, fromskew);
480 main(int argc, char **argv)
488 unsigned long nx, ny;
489 unsigned short BitsPerSample, SamplesPerPixel;
490 int isColorMapped, isPliFile;
491 unsigned char *ColorMap;
495 fprintf(stderr,"usage: %s tiff_file\n",argv[0]);
498 tif = (TIFF *)PLIGetImage(argv[1], (void *) &data, &ColorMap,
499 &nx, &ny, &BitsPerSample, &SamplesPerPixel,
500 &isColorMapped, &isPliFile);
503 if (TIFFImageIterBegin(&img, tif, stop, emsg)) {
504 /* Here need to set data and callback function! */
506 img.callback = TestContigCallback;
508 img.callback = TestSepCallback;
510 ok = TIFFImageIterGet(&img, NULL, img.width, img.height);
511 TIFFImageIterEnd(&img);
513 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), emsg);