New comit of SDL2
[supertux.git] / src / SDL2 / external / tiff-4.0.3 / contrib / pds / tif_imageiter.c
1 /* $Header: /cvs/maptools/cvsroot/libtiff/contrib/pds/tif_imageiter.c,v 1.4 2010-06-08 18:55:15 bfriesen 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
519 /*
520  * Local Variables:
521  * mode: c
522  * c-basic-offset: 8
523  * fill-column: 78
524  * End:
525  */