]> git.saurik.com Git - wxWidgets.git/blob - src/tiff/contrib/pds/tif_imageiter.c
Fix wxMac preprocessor check in wxWebView code.
[wxWidgets.git] / src / tiff / contrib / pds / tif_imageiter.c
1 /* $Header: /cvs/maptools/cvsroot/libtiff/contrib/pds/tif_imageiter.c,v 1.3 2005/12/21 12:23:13 joris Exp $ */
2
3 /*
4 * Copyright (c) 1991-1996 Sam Leffler
5 * Copyright (c) 1991-1996 Silicon Graphics, Inc.
6 *
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.
14 *
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.
18 *
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
24 * OF THIS SOFTWARE.
25 */
26
27 /*
28 * TIFF Library
29 *
30 * Written by Conrad J. Poelman, PL/WSAT, Kirtland AFB, NM on 26 Mar 96.
31 *
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.
38 *
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.
42 *
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.
47 *
48 */
49 #include "tiffiop.h"
50 #include "tif_imageiter.h"
51 #include <assert.h>
52 #include <stdio.h>
53
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);
58
59 static const char photoTag[] = "PhotometricInterpretation";
60
61 static int
62 isCCITTCompression(TIFF* tif)
63 {
64 uint16 compress;
65 TIFFGetField(tif, TIFFTAG_COMPRESSION, &compress);
66 return (compress == COMPRESSION_CCITTFAX3 ||
67 compress == COMPRESSION_CCITTFAX4 ||
68 compress == COMPRESSION_CCITTRLE ||
69 compress == COMPRESSION_CCITTRLEW);
70 }
71
72 int
73 TIFFImageIterBegin(TIFFImageIter* img, TIFF* tif, int stop, char emsg[1024])
74 {
75 uint16* sampleinfo;
76 uint16 extrasamples;
77 uint16 planarconfig;
78 int colorchannels;
79
80 img->tif = tif;
81 img->stoponerr = stop;
82 TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &img->bitspersample);
83 img->alpha = 0;
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];
92 break;
93 }
94 colorchannels = img->samplesperpixel - extrasamples;
95 TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig);
96 if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) {
97 switch (colorchannels) {
98 case 1:
99 if (isCCITTCompression(tif))
100 img->photometric = PHOTOMETRIC_MINISWHITE;
101 else
102 img->photometric = PHOTOMETRIC_MINISBLACK;
103 break;
104 case 3:
105 img->photometric = PHOTOMETRIC_RGB;
106 break;
107 default:
108 sprintf(emsg, "Missing needed %s tag", photoTag);
109 return (0);
110 }
111 }
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");
117 return (0);
118 }
119 /* fall thru... */
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) {
124 sprintf(emsg,
125 "Sorry, can not handle contiguous data with %s=%d, and %s=%d",
126 photoTag, img->photometric,
127 "Samples/pixel", img->samplesperpixel);
128 return (0);
129 }
130 */
131 break;
132 case PHOTOMETRIC_YCBCR:
133 if (planarconfig != PLANARCONFIG_CONTIG) {
134 sprintf(emsg, "Sorry, can not handle YCbCr images with %s=%d",
135 "Planarconfiguration", planarconfig);
136 return (0);
137 }
138 /* It would probably be nice to have a reality check here. */
139 { uint16 compress;
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;
146 }
147 }
148 break;
149 case PHOTOMETRIC_RGB:
150 if (colorchannels < 3) {
151 sprintf(emsg, "Sorry, can not handle RGB image with %s=%d",
152 "Color channels", colorchannels);
153 return (0);
154 }
155 break;
156 case PHOTOMETRIC_SEPARATED: {
157 uint16 inkset;
158 TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset);
159 if (inkset != INKSET_CMYK) {
160 sprintf(emsg, "Sorry, can not handle separated image with %s=%d",
161 "InkSet", inkset);
162 return (0);
163 }
164 if (img->samplesperpixel != 4) {
165 sprintf(emsg, "Sorry, can not handle separated image with %s=%d",
166 "Samples/pixel", img->samplesperpixel);
167 return (0);
168 }
169 break;
170 }
171 default:
172 sprintf(emsg, "Sorry, can not handle image with %s=%d",
173 photoTag, img->photometric);
174 return (0);
175 }
176 TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &img->width);
177 TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &img->height);
178
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;
186 /* fall thru... */
187 case ORIENTATION_BOTLEFT:
188 break;
189 case ORIENTATION_TOPRIGHT:
190 case ORIENTATION_RIGHTTOP: /* XXX */
191 case ORIENTATION_LEFTTOP: /* XXX */
192 default:
193 TIFFWarning(TIFFFileName(tif), "using top-left orientation");
194 img->orientation = ORIENTATION_TOPLEFT;
195 /* fall thru... */
196 case ORIENTATION_TOPLEFT:
197 break;
198 }
199
200 img->isContig =
201 !(planarconfig == PLANARCONFIG_SEPARATE && colorchannels > 1);
202 if (img->isContig) {
203 img->get = TIFFIsTiled(tif) ? gtTileContig : gtStripContig;
204 } else {
205 img->get = TIFFIsTiled(tif) ? gtTileSeparate : gtStripSeparate;
206 }
207 return (1);
208 }
209
210 int
211 TIFFImageIterGet(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
212 {
213 if (img->get == NULL) {
214 TIFFErrorExt(img->tif->tif_clientdata, TIFFFileName(img->tif), "No \"get\" routine setup");
215 return (0);
216 }
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");
220 return (0);
221 }
222 return (*img->get)(img, udata, w, h);
223 }
224
225 TIFFImageIterEnd(TIFFImageIter* img)
226 {
227 /* Nothing to free... ? */
228 }
229
230 /*
231 * Read the specified image into an ABGR-format raster.
232 */
233 int
234 TIFFReadImageIter(TIFF* tif,
235 uint32 rwidth, uint32 rheight, uint8* raster, int stop)
236 {
237 char emsg[1024];
238 TIFFImageIter img;
239 int ok;
240
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);
245 } else {
246 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), emsg);
247 ok = 0;
248 }
249 return (ok);
250 }
251
252
253 /*
254 * Get an tile-organized image that has
255 * PlanarConfiguration contiguous if SamplesPerPixel > 1
256 * or
257 * SamplesPerPixel == 1
258 */
259 static int
260 gtTileContig(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
261 {
262 TIFF* tif = img->tif;
263 ImageIterTileContigRoutine callback = img->callback.contig;
264 uint16 orientation;
265 uint32 col, row;
266 uint32 tw, th;
267 u_char* buf;
268 int32 fromskew;
269 uint32 nrow;
270
271 buf = (u_char*) _TIFFmalloc(TIFFTileSize(tif));
272 if (buf == 0) {
273 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer");
274 return (0);
275 }
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)
283 break;
284 if (col + tw > w) {
285 /*
286 * Tile is clipped horizontally. Calculate
287 * visible portion and skewing factors.
288 */
289 uint32 npix = w - col;
290 fromskew = tw - npix;
291 (*callback)(img, udata, col, row, npix, nrow, fromskew, buf);
292 } else {
293 (*callback)(img, udata, col, row, tw, nrow, 0, buf);
294 }
295 }
296 }
297 _TIFFfree(buf);
298 return (1);
299 }
300
301 /*
302 * Get an tile-organized image that has
303 * SamplesPerPixel > 1
304 * PlanarConfiguration separated
305 * We assume that all such images are RGB.
306 */
307 static int
308 gtTileSeparate(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
309 {
310 TIFF* tif = img->tif;
311 ImageIterTileSeparateRoutine callback = img->callback.separate;
312 uint16 orientation;
313 uint32 col, row;
314 uint32 tw, th;
315 u_char* buf;
316 u_char* r;
317 u_char* g;
318 u_char* b;
319 u_char* a;
320 tsize_t tilesize;
321 int32 fromskew;
322 int alpha = img->alpha;
323 uint32 nrow;
324
325 tilesize = TIFFTileSize(tif);
326 buf = (u_char*) _TIFFmalloc(4*tilesize);
327 if (buf == 0) {
328 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer");
329 return (0);
330 }
331 r = buf;
332 g = r + tilesize;
333 b = g + tilesize;
334 a = b + tilesize;
335 if (!alpha)
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)
344 break;
345 if (TIFFReadTile(tif, g, col, row,0,1) < 0 && img->stoponerr)
346 break;
347 if (TIFFReadTile(tif, b, col, row,0,2) < 0 && img->stoponerr)
348 break;
349 if (alpha && TIFFReadTile(tif,a,col,row,0,3) < 0 && img->stoponerr)
350 break;
351 if (col + tw > w) {
352 /*
353 * Tile is clipped horizontally. Calculate
354 * visible portion and skewing factors.
355 */
356 uint32 npix = w - col;
357 fromskew = tw - npix;
358 (*callback)(img, udata, col, row, npix, nrow, fromskew, r, g, b, a);
359 } else {
360 (*callback)(img, udata, col, row, tw, nrow, 0, r, g, b, a);
361 }
362 }
363 }
364 _TIFFfree(buf);
365 return (1);
366 }
367
368 /*
369 * Get a strip-organized image that has
370 * PlanarConfiguration contiguous if SamplesPerPixel > 1
371 * or
372 * SamplesPerPixel == 1
373 */
374 static int
375 gtStripContig(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
376 {
377 TIFF* tif = img->tif;
378 ImageIterTileContigRoutine callback = img->callback.contig;
379 uint16 orientation;
380 uint32 row, nrow;
381 u_char* buf;
382 uint32 rowsperstrip;
383 uint32 imagewidth = img->width;
384 tsize_t scanline;
385 int32 fromskew;
386
387 buf = (u_char*) _TIFFmalloc(TIFFStripSize(tif));
388 if (buf == 0) {
389 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for strip buffer");
390 return (0);
391 }
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)
400 break;
401 (*callback)(img, udata, 0, row, w, nrow, fromskew, buf);
402 }
403 _TIFFfree(buf);
404 return (1);
405 }
406
407 /*
408 * Get a strip-organized image with
409 * SamplesPerPixel > 1
410 * PlanarConfiguration separated
411 * We assume that all such images are RGB.
412 */
413 static int
414 gtStripSeparate(TIFFImageIter* img, void *udata, uint32 w, uint32 h)
415 {
416 TIFF* tif = img->tif;
417 ImageIterTileSeparateRoutine callback = img->callback.separate;
418 uint16 orientation;
419 u_char *buf;
420 u_char *r, *g, *b, *a;
421 uint32 row, nrow;
422 tsize_t scanline;
423 uint32 rowsperstrip;
424 uint32 imagewidth = img->width;
425 tsize_t stripsize;
426 int32 fromskew;
427 int alpha = img->alpha;
428
429 stripsize = TIFFStripSize(tif);
430 r = buf = (u_char *)_TIFFmalloc(4*stripsize);
431 if (buf == 0) {
432 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for tile buffer");
433 return (0);
434 }
435 g = r + stripsize;
436 b = g + stripsize;
437 a = b + stripsize;
438 if (!alpha)
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)
448 break;
449 if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 1),
450 g, nrow*scanline) < 0 && img->stoponerr)
451 break;
452 if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 2),
453 b, nrow*scanline) < 0 && img->stoponerr)
454 break;
455 if (alpha &&
456 (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 3),
457 a, nrow*scanline) < 0 && img->stoponerr))
458 break;
459 (*callback)(img, udata, 0, row, w, nrow, fromskew, r, g, b, a);
460 }
461 _TIFFfree(buf);
462 return (1);
463 }
464
465 DECLAREContigCallbackFunc(TestContigCallback)
466 {
467 printf("Contig Callback called with x = %d, y = %d, w = %d, h = %d, fromskew = %d\n",
468 x, y, w, h, fromskew);
469 }
470
471
472 DECLARESepCallbackFunc(TestSepCallback)
473 {
474 printf("Sep Callback called with x = %d, y = %d, w = %d, h = %d, fromskew = %d\n",
475 x, y, w, h, fromskew);
476 }
477
478
479 #ifdef MAIN
480 main(int argc, char **argv)
481 {
482 char emsg[1024];
483 TIFFImageIter img;
484 int ok;
485 int stop = 1;
486
487 TIFF *tif;
488 unsigned long nx, ny;
489 unsigned short BitsPerSample, SamplesPerPixel;
490 int isColorMapped, isPliFile;
491 unsigned char *ColorMap;
492 unsigned char *data;
493
494 if (argc < 2) {
495 fprintf(stderr,"usage: %s tiff_file\n",argv[0]);
496 exit(1);
497 }
498 tif = (TIFF *)PLIGetImage(argv[1], (void *) &data, &ColorMap,
499 &nx, &ny, &BitsPerSample, &SamplesPerPixel,
500 &isColorMapped, &isPliFile);
501 if (tif != NULL) {
502
503 if (TIFFImageIterBegin(&img, tif, stop, emsg)) {
504 /* Here need to set data and callback function! */
505 if (img.isContig) {
506 img.callback = TestContigCallback;
507 } else {
508 img.callback = TestSepCallback;
509 }
510 ok = TIFFImageIterGet(&img, NULL, img.width, img.height);
511 TIFFImageIterEnd(&img);
512 } else {
513 TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), emsg);
514 }
515 }
516
517 }
518 #endif