1 /* $Header: /cvs/maptools/cvsroot/libtiff/contrib/pds/tif_imageiter.c,v 1.3 2005/12/21 12:23:13 joris 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
);