]>
Commit | Line | Data |
---|---|---|
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 |