"Fossies" - the Fresh Open Source Software Archive 
Member "libgd-2.3.3/src/gd_tiff.c" (11 Sep 2021, 27878 Bytes) of package /linux/www/libgd-2.3.3.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
1 /*
2 TIFF - Tagged Image File Format Encapsulation for GD Library
3
4 gd_tiff.c
5 Copyright (C) Pierre-A. Joye, M. Retallack
6
7 ---------------------------------------------------------------------------
8 **
9 ** Permission to use, copy, modify, and distribute this software and its
10 ** documentation for any purpose and without fee is hereby granted, provided
11 ** that the above copyright notice appear in all copies and that both that
12 ** copyright notice and this permission notice appear in supporting
13 ** documentation. This software is provided "as is" without express or
14 ** implied warranty.
15 **
16 ---------------------------------------------------------------------------
17 Ctx code written by M. Retallack
18
19 Todo:
20
21 If we fail - cleanup
22 Writer: Use gd error function, overflow check may not be necessary as
23 we write our own data (check already done)
24
25 Implement 2 color black/white saving using group4 fax compression
26 Implement function to specify encoding to use when writing tiff data
27
28 ----------------------------------------------------------------------------
29 */
30
31 /**
32 * File: TIFF IO
33 *
34 * Read and write TIFF images.
35 *
36 * There is only most basic support for the TIFF format available for now;
37 * for instance, multiple pages are not yet supported.
38 */
39
40 #ifdef HAVE_CONFIG_H
41 # include "config.h"
42 #endif
43
44 #include "gd.h"
45 #include "gd_errors.h"
46 #include "gd_intern.h"
47 #include "gdfonts.h"
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <limits.h>
51
52 #include "gdhelpers.h"
53
54 #ifdef HAVE_LIBTIFF
55
56 #include "tiff.h"
57 #include "tiffio.h"
58
59 #define GD_SUCCESS 1
60 #define GD_FAILURE 0
61
62 #define TRUE 1
63 #define FALSE 0
64
65 /* I define those here until the new formats
66 * are commited. We can then rely on the global
67 * def
68 */
69 #define GD_PALETTE 1
70 #define GD_TRUECOLOR 2
71 #define GD_GRAY 3
72 #define GD_INDEXED 4
73 #define GD_RGB 5
74
75 typedef struct tiff_handle {
76 int size;
77 int pos;
78 gdIOCtx *ctx;
79 int written;
80 }
81 tiff_handle;
82
83 /*
84 Functions for reading, writing and seeking in gdIOCtx
85 This allows for non-file i/o operations with no
86 explicit use of libtiff fileio wrapper functions
87
88 Note: because libtiff requires random access, but gdIOCtx
89 only supports streams, all writes are buffered
90 into memory and written out on close, also all
91 reads are done from a memory mapped version of the
92 tiff (assuming one already exists)
93 */
94
95 tiff_handle * new_tiff_handle(gdIOCtx *g)
96 {
97 tiff_handle * t;
98
99 if (!g) {
100 gd_error("Cannot create a new tiff handle, missing Ctx argument");
101 return NULL;
102 }
103
104 t = (tiff_handle *) gdMalloc(sizeof(tiff_handle));
105 if (!t) {
106 gd_error("Failed to allocate a new tiff handle");
107 return NULL;
108 }
109
110 t->size = 0;
111 t->pos = 0;
112 t->ctx = g;
113 t->written = 0;
114
115 return t;
116 }
117
118 /* TIFFReadWriteProc tiff_readproc - Will use gdIOCtx procs to read required
119 (previously written) TIFF file content */
120 static tsize_t tiff_readproc(thandle_t clientdata, tdata_t data, tsize_t size)
121 {
122 tiff_handle *th = (tiff_handle *)clientdata;
123 gdIOCtx *ctx = th->ctx;
124
125 size = (ctx->getBuf)(ctx, data, size);
126
127 return size;
128 }
129
130 /* TIFFReadWriteProc tiff_writeproc - Will use gdIOCtx procs to write out
131 TIFF data */
132 static tsize_t tiff_writeproc(thandle_t clientdata, tdata_t data, tsize_t size)
133 {
134 tiff_handle *th = (tiff_handle *)clientdata;
135 gdIOCtx *ctx = th->ctx;
136
137 size = (ctx->putBuf)(ctx, data, size);
138 if(size + th->pos>th->size) {
139 th->size = size + th->pos;
140 th->pos += size;
141 }
142
143 return size;
144 }
145
146 /* TIFFSeekProc tiff_seekproc
147 * used to move around the partially written TIFF */
148 static toff_t tiff_seekproc(thandle_t clientdata, toff_t offset, int from)
149 {
150 tiff_handle *th = (tiff_handle *)clientdata;
151 gdIOCtx *ctx = th->ctx;
152 int result;
153
154 switch(from) {
155 default:
156 case SEEK_SET:
157 /* just use offset */
158 break;
159
160 case SEEK_END:
161 /* invert offset, so that it is from start, not end as supplied */
162 offset = th->size + offset;
163 break;
164
165 case SEEK_CUR:
166 /* add current position to translate it to 'from start',
167 * not from durrent as supplied
168 */
169 offset += th->pos;
170 break;
171 }
172
173 /* now, move pos in both io context and buf */
174 if((result = (ctx->seek)(ctx, offset))) {
175 th->pos = offset;
176 }
177
178 return result ? offset : (toff_t)-1;
179 }
180
181 /* TIFFCloseProc tiff_closeproc - used to finally close the TIFF file */
182 static int tiff_closeproc(thandle_t clientdata)
183 {
184 (void)clientdata;
185 /*tiff_handle *th = (tiff_handle *)clientdata;
186 gdIOCtx *ctx = th->ctx;
187
188 (ctx->gd_free)(ctx);*/
189
190 return 0;
191 }
192
193 /* TIFFSizeProc tiff_sizeproc */
194 static toff_t tiff_sizeproc(thandle_t clientdata)
195 {
196 tiff_handle *th = (tiff_handle *)clientdata;
197 return th->size;
198 }
199
200 /* TIFFMapFileProc tiff_mapproc() */
201 static int tiff_mapproc(thandle_t h, tdata_t *d, toff_t *o)
202 {
203 (void)h;
204 (void)d;
205 (void)o;
206 return 0;
207 }
208
209 /* TIFFUnmapFileProc tiff_unmapproc */
210 static void tiff_unmapproc(thandle_t h, tdata_t d, toff_t o)
211 {
212 (void)h;
213 (void)d;
214 (void)o;
215 }
216
217
218 /* tiffWriter
219 * ----------
220 * Write the gd image as a tiff file (called by gdImageTiffCtx)
221 * Parameters are:
222 * image: gd image structure;
223 * out: the stream where to write
224 * bitDepth: depth in bits of each pixel
225 */
226 void tiffWriter(gdImagePtr image, gdIOCtx *out, int bitDepth)
227 {
228 int x, y;
229 int i;
230 int r, g, b, a;
231 TIFF *tiff;
232 int width, height;
233 int color;
234 char *scan;
235 int samplesPerPixel = 3;
236 int bitsPerSample;
237 int transparentColorR = -1;
238 int transparentColorG = -1;
239 int transparentColorB = -1;
240 uint16_t extraSamples[1];
241 uint16_t *colorMapRed = NULL;
242 uint16_t *colorMapGreen = NULL;
243 uint16_t *colorMapBlue = NULL;
244
245 tiff_handle *th;
246
247 th = new_tiff_handle(out);
248 if (!th) {
249 return;
250 }
251 extraSamples[0] = EXTRASAMPLE_ASSOCALPHA;
252
253 /* read in the width/height of gd image */
254 width = gdImageSX(image);
255 height = gdImageSY(image);
256
257 /* reset clip region to whole image */
258 gdImageSetClip(image, 0, 0, width, height);
259
260 /* handle old-style single-colour mapping to 100% transparency */
261 if(image->transparent != -1) {
262 /* set our 100% transparent colour value */
263 transparentColorR = gdImageRed(image, image->transparent);
264 transparentColorG = gdImageGreen(image, image->transparent);
265 transparentColorB = gdImageBlue(image, image->transparent);
266 }
267
268 /* Open tiff file writing routines, but use special read/write/seek
269 * functions so that tiff lib writes correct bits of tiff content to
270 * correct areas of file opened and modifieable by the gdIOCtx functions
271 */
272 tiff = TIFFClientOpen("", "w", th, tiff_readproc,
273 tiff_writeproc,
274 tiff_seekproc,
275 tiff_closeproc,
276 tiff_sizeproc,
277 tiff_mapproc,
278 tiff_unmapproc);
279
280 TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, width);
281 TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, height);
282 TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
283 TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
284 TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC,
285 (bitDepth == 24) ? PHOTOMETRIC_RGB : PHOTOMETRIC_PALETTE);
286
287 bitsPerSample = (bitDepth == 24 || bitDepth == 8) ? 8 : 1;
288 TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, bitsPerSample);
289
290 TIFFSetField(tiff, TIFFTAG_XRESOLUTION, (float)image->res_x);
291 TIFFSetField(tiff, TIFFTAG_YRESOLUTION, (float)image->res_y);
292
293 /* build the color map for 8 bit images */
294 if(bitDepth != 24) {
295 colorMapRed = (uint16_t *) gdMalloc(3 * (1 << bitsPerSample));
296 if (!colorMapRed) {
297 gdFree(th);
298 return;
299 }
300 colorMapGreen = (uint16_t *) gdMalloc(3 * (1 << bitsPerSample));
301 if (!colorMapGreen) {
302 gdFree(colorMapRed);
303 gdFree(th);
304 return;
305 }
306 colorMapBlue = (uint16_t *) gdMalloc(3 * (1 << bitsPerSample));
307 if (!colorMapBlue) {
308 gdFree(colorMapRed);
309 gdFree(colorMapGreen);
310 gdFree(th);
311 return;
312 }
313
314 for(i = 0; i < image->colorsTotal; i++) {
315 colorMapRed[i] = gdImageRed(image,i) + (gdImageRed(image,i) * 256);
316 colorMapGreen[i] = gdImageGreen(image,i)+(gdImageGreen(image,i)*256);
317 colorMapBlue[i] = gdImageBlue(image,i) + (gdImageBlue(image,i)*256);
318 }
319
320 TIFFSetField(tiff, TIFFTAG_COLORMAP, colorMapRed, colorMapGreen,
321 colorMapBlue);
322 samplesPerPixel = 1;
323 }
324
325 /* here, we check if the 'save alpha' flag is set on the source gd image */
326 if ((bitDepth == 24) &&
327 (image->saveAlphaFlag || image->transparent != -1)) {
328 /* so, we need to store the alpha values too!
329 * Also, tell TIFF what the extra sample means (associated alpha) */
330 samplesPerPixel = 4;
331 TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, samplesPerPixel);
332 TIFFSetField(tiff, TIFFTAG_EXTRASAMPLES, 1, extraSamples);
333 } else {
334 TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, samplesPerPixel);
335 }
336
337 TIFFSetField(tiff, TIFFTAG_ROWSPERSTRIP, 1);
338
339 if(overflow2(width, samplesPerPixel)) {
340 if (colorMapRed) gdFree(colorMapRed);
341 if (colorMapGreen) gdFree(colorMapGreen);
342 if (colorMapBlue) gdFree(colorMapBlue);
343 gdFree(th);
344 return;
345 }
346
347 if(!(scan = (char *)gdMalloc(width * samplesPerPixel))) {
348 if (colorMapRed) gdFree(colorMapRed);
349 if (colorMapGreen) gdFree(colorMapGreen);
350 if (colorMapBlue) gdFree(colorMapBlue);
351 gdFree(th);
352 return;
353 }
354
355 /* loop through y-coords, and x-coords */
356 for(y = 0; y < height; y++) {
357 for(x = 0; x < width; x++) {
358 /* generate scan line for writing to tiff */
359 color = gdImageGetPixel(image, x, y);
360
361 a = (127 - gdImageAlpha(image, color)) * 2;
362 a = (a == 0xfe) ? 0xff : a & 0xff;
363 b = gdImageBlue(image, color);
364 g = gdImageGreen(image, color);
365 r = gdImageRed(image, color);
366
367 /* if this pixel has the same RGB as the transparent colour,
368 * then set alpha fully transparent */
369 if (transparentColorR == r &&
370 transparentColorG == g &&
371 transparentColorB == b) {
372 a = 0x00;
373 }
374
375 if(bitDepth != 24) {
376 /* write out 1 or 8 bit value in 1 byte
377 * (currently treats 1bit as 8bit) */
378 scan[(x * samplesPerPixel) + 0] = color;
379 } else {
380 /* write out 24 bit value in 3 (or 4 if transparent) bytes */
381 if(image->saveAlphaFlag || image->transparent != -1) {
382 scan[(x * samplesPerPixel) + 3] = a;
383 }
384
385 scan[(x * samplesPerPixel) + 2] = b;
386 scan[(x * samplesPerPixel) + 1] = g;
387 scan[(x * samplesPerPixel) + 0] = r;
388 }
389 }
390
391 /* Write the scan line to the tiff */
392 if(TIFFWriteEncodedStrip(tiff, y, scan, width * samplesPerPixel) == -1) {
393 if (colorMapRed) gdFree(colorMapRed);
394 if (colorMapGreen) gdFree(colorMapGreen);
395 if (colorMapBlue) gdFree(colorMapBlue);
396 gdFree(th);
397 /* error handler here */
398 gd_error("Could not create TIFF\n");
399 return;
400 }
401 }
402
403 /* now cloase and free up resources */
404 TIFFClose(tiff);
405 gdFree(scan);
406 gdFree(th);
407
408 if(bitDepth != 24) {
409 gdFree(colorMapRed);
410 gdFree(colorMapGreen);
411 gdFree(colorMapBlue);
412 }
413 }
414
415 /*
416 Function: gdImageTiffCtx
417
418 Write the gd image as a tiff file.
419
420 Parameters:
421
422 image - gd image structure;
423 out - the stream where to write
424 */
425 BGD_DECLARE(void) gdImageTiffCtx(gdImagePtr image, gdIOCtx *out)
426 {
427 int clipx1P, clipy1P, clipx2P, clipy2P;
428 int bitDepth = 24;
429
430 /* First, switch off clipping, or we'll not get all the image! */
431 gdImageGetClip(image, &clipx1P, &clipy1P, &clipx2P, &clipy2P);
432
433 /* use the appropriate routine depending on the bit depth of the image */
434 if(image->trueColor) {
435 bitDepth = 24;
436 } else if(image->colorsTotal == 2) {
437 bitDepth = 1;
438 } else {
439 bitDepth = 8;
440 }
441
442 tiffWriter(image, out, bitDepth);
443
444 /* reset clipping area to the gd image's original values */
445 gdImageSetClip(image, clipx1P, clipy1P, clipx2P, clipy2P);
446 }
447
448 /* Check if we are really in 8bit mode */
449 static int checkColorMap(n, r, g, b)
450 int n;
451 uint16_t *r, *g, *b;
452 {
453 while (n-- > 0)
454 if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
455 return (16);
456 return (8);
457 }
458
459
460 /* Read and convert a TIFF colormap */
461 static int readTiffColorMap(gdImagePtr im, TIFF *tif, char is_bw, int photometric)
462 {
463 uint16_t *redcmap, *greencmap, *bluecmap;
464 uint16_t bps;
465 int i;
466
467 if (is_bw) {
468 if (photometric == PHOTOMETRIC_MINISWHITE) {
469 gdImageColorAllocate(im, 255,255,255);
470 gdImageColorAllocate(im, 0, 0, 0);
471 } else {
472 gdImageColorAllocate(im, 0, 0, 0);
473 gdImageColorAllocate(im, 255,255,255);
474 }
475 } else {
476 uint16_t min_sample_val, max_sample_val;
477
478 if (!TIFFGetField(tif, TIFFTAG_MINSAMPLEVALUE, &min_sample_val)) {
479 min_sample_val = 0;
480 }
481 if (!TIFFGetField(tif, TIFFTAG_MAXSAMPLEVALUE, &max_sample_val)) {
482 max_sample_val = 255;
483 }
484
485 if (photometric == PHOTOMETRIC_MINISBLACK || photometric == PHOTOMETRIC_MINISWHITE) {
486 /* TODO: use TIFFTAG_MINSAMPLEVALUE and TIFFTAG_MAXSAMPLEVALUE */
487 /* Gray level palette */
488 for (i=min_sample_val; i <= max_sample_val; i++) {
489 gdImageColorAllocate(im, i,i,i);
490 }
491 return GD_SUCCESS;
492
493 } else if (!TIFFGetField(tif, TIFFTAG_COLORMAP, &redcmap, &greencmap, &bluecmap)) {
494 gd_error("Cannot read the color map");
495 return GD_FAILURE;
496 }
497
498 TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bps);
499
500 #define CVT(x) (((x) * 255) / ((1L<<16)-1))
501 if (checkColorMap(1<<bps, redcmap, greencmap, bluecmap) == 16) {
502 for (i = (1<<bps)-1; i > 0; i--) {
503 redcmap[i] = CVT(redcmap[i]);
504 greencmap[i] = CVT(greencmap[i]);
505 bluecmap[i] = CVT(bluecmap[i]);
506 }
507 }
508 for (i = 0; i < 256; i++) {
509 gdImageColorAllocate(im, redcmap[i], greencmap[i], bluecmap[i]);
510 }
511 #undef CVT
512 }
513 return GD_SUCCESS;
514 }
515
516 static void readTiffBw (const unsigned char *src,
517 gdImagePtr im,
518 uint16_t photometric,
519 int startx,
520 int starty,
521 int width,
522 int height,
523 char has_alpha,
524 int extra,
525 int align)
526 {
527 int x = startx, y = starty;
528
529 (void)has_alpha;
530 (void)extra;
531 (void)align;
532
533 for (y = starty; y < starty + height; y++) {
534 for (x = startx; x < startx + width;) {
535 register unsigned char curr = *src++;
536 register unsigned char mask;
537
538 if (photometric == PHOTOMETRIC_MINISWHITE) {
539 curr = ~curr;
540 }
541 for (mask = 0x80; mask != 0 && x < startx + width; x++, mask >>= 1) {
542 gdImageSetPixel(im, x, y, ((curr & mask) != 0)?0:1);
543 }
544 }
545 }
546 }
547
548 static void readTiff8bit (const unsigned char *src,
549 gdImagePtr im,
550 uint16_t photometric,
551 int startx,
552 int starty,
553 int width,
554 int height,
555 char has_alpha,
556 int extra,
557 int align)
558 {
559 int red, green, blue, alpha;
560 int x, y;
561
562 (void)extra;
563 (void)align;
564
565 switch (photometric) {
566 case PHOTOMETRIC_PALETTE:
567 /* Palette has no alpha (see TIFF specs for more details */
568 for (y = starty; y < starty + height; y++) {
569 for (x = startx; x < startx + width; x++) {
570 gdImageSetPixel(im, x, y,*(src++));
571 }
572 }
573 break;
574
575 case PHOTOMETRIC_RGB:
576 if (has_alpha) {
577 gdImageAlphaBlending(im, 0);
578 gdImageSaveAlpha(im, 1);
579
580 for (y = starty; y < starty + height; y++) {
581 for (x = startx; x < startx + width; x++) {
582 red = *src++;
583 green = *src++;
584 blue = *src++;
585 alpha = *src++;
586 red = MIN (red, alpha);
587 blue = MIN (blue, alpha);
588 green = MIN (green, alpha);
589
590 if (alpha) {
591 gdImageSetPixel(im, x, y, gdTrueColorAlpha(red * 255 / alpha, green * 255 / alpha, blue * 255 /alpha, gdAlphaMax - (alpha >> 1)));
592 } else {
593 gdImageSetPixel(im, x, y, gdTrueColorAlpha(red, green, blue, gdAlphaMax - (alpha >> 1)));
594 }
595 }
596 }
597
598 } else {
599 for (y = 0; y < height; y++) {
600 for (x = 0; x < width; x++) {
601 register unsigned char r = *src++;
602 register unsigned char g = *src++;
603 register unsigned char b = *src++;
604
605 gdImageSetPixel(im, x, y, gdTrueColor(r, g, b));
606 }
607 }
608 }
609 break;
610
611 case PHOTOMETRIC_MINISWHITE:
612 if (has_alpha) {
613 /* We don't process the extra yet */
614 } else {
615 for (y = starty; y < starty + height; y++) {
616 for (x = startx; x < startx + width; x++) {
617 gdImageSetPixel(im, x, y, ~(*src++));
618 }
619 }
620 }
621 break;
622
623 case PHOTOMETRIC_MINISBLACK:
624 if (has_alpha) {
625 /* We don't process the extra yet */
626 } else {
627 for (y = starty; y < height; y++) {
628 for (x = 0; x < width; x++) {
629 gdImageSetPixel(im, x, y, *src++);
630 }
631 }
632 }
633 break;
634 }
635 }
636
637 static int createFromTiffTiles(TIFF *tif, gdImagePtr im, uint16_t bps, uint16_t photometric,
638 char has_alpha, char is_bw, int extra)
639 {
640 uint16_t planar;
641 int im_width, im_height;
642 int tile_width, tile_height;
643 int x, y, height, width;
644 unsigned char *buffer;
645 int success = GD_SUCCESS;
646
647 if (!TIFFGetField (tif, TIFFTAG_PLANARCONFIG, &planar)) {
648 planar = PLANARCONFIG_CONTIG;
649 }
650 if (TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &im_width) == 0 ||
651 TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &im_height) == 0 ||
652 TIFFGetField (tif, TIFFTAG_TILEWIDTH, &tile_width) == 0 ||
653 TIFFGetField (tif, TIFFTAG_TILELENGTH, &tile_height) == 0) {
654 return FALSE;
655 }
656
657 buffer = (unsigned char *) gdMalloc (TIFFTileSize (tif));
658 if (!buffer) {
659 return FALSE;
660 }
661
662 for (y = 0; y < im_height; y += tile_height) {
663 for (x = 0; x < im_width; x += tile_width) {
664 if (TIFFReadTile(tif, buffer, x, y, 0, 0) < 0) {
665 success = GD_FAILURE;
666 goto end;
667 }
668 width = MIN(im_width - x, tile_width);
669 height = MIN(im_height - y, tile_height);
670 if (bps == 16) {
671 } else if (bps == 8) {
672 readTiff8bit(buffer, im, photometric, x, y, width, height, has_alpha, extra, 0);
673 } else if (is_bw) {
674 readTiffBw(buffer, im, photometric, x, y, width, height, has_alpha, extra, 0);
675 } else {
676 /* TODO: implement some default reader or detect this case earlier use force_rgb */
677 }
678 }
679 }
680 end:
681 gdFree(buffer);
682 return success;
683 }
684
685 static int createFromTiffLines(TIFF *tif, gdImagePtr im, uint16_t bps, uint16_t photometric,
686 char has_alpha, char is_bw, int extra)
687 {
688 uint16_t planar;
689 uint32_t im_height, im_width, y;
690
691 unsigned char *buffer;
692 int success = GD_SUCCESS;
693
694 if (!TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planar)) {
695 planar = PLANARCONFIG_CONTIG;
696 }
697
698 if (!TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &im_height)) {
699 gd_error("Can't fetch TIFF height\n");
700 return FALSE;
701 }
702
703 if (!TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &im_width)) {
704 gd_error("Can't fetch TIFF width \n");
705 return FALSE;
706 }
707
708 buffer = (unsigned char *)gdMalloc(im_width * 4);
709 if (!buffer) {
710 return GD_FAILURE;
711 }
712 if (planar == PLANARCONFIG_CONTIG) {
713 switch (bps) {
714 case 16:
715 /* TODO
716 * or simply use force_rgba
717 */
718 break;
719
720 case 8:
721 for (y = 0; y < im_height; y++ ) {
722 if (TIFFReadScanline (tif, buffer, y, 0) < 0) {
723 gd_error("Error while reading scanline %i", y);
724 success = GD_FAILURE;
725 break;
726 }
727 /* reading one line at a time */
728 readTiff8bit(buffer, im, photometric, 0, y, im_width, 1, has_alpha, extra, 0);
729 }
730 break;
731
732 default:
733 if (is_bw) {
734 for (y = 0; y < im_height; y++ ) {
735 if (TIFFReadScanline (tif, buffer, y, 0) < 0) {
736 gd_error("Error while reading scanline %i", y);
737 success = GD_FAILURE;
738 break;
739 }
740 /* reading one line at a time */
741 readTiffBw(buffer, im, photometric, 0, y, im_width, 1, has_alpha, extra, 0);
742 }
743 } else {
744 /* TODO: implement some default reader or detect this case earlier > force_rgb */
745 }
746 break;
747 }
748 } else {
749 /* TODO: implement a reader for separate panes. We detect this case earlier for now and use force_rgb */
750 }
751
752 gdFree(buffer);
753 return success;
754 }
755
756 static int createFromTiffRgba(TIFF * tif, gdImagePtr im)
757 {
758 int a;
759 int x, y;
760 int alphaBlendingFlag = 0;
761 int color;
762 int width = im->sx;
763 int height = im->sy;
764 uint32_t *buffer;
765 uint32_t rgba;
766 int success;
767
768 buffer = (uint32_t *) gdCalloc(sizeof(uint32_t), width * height);
769 if (!buffer) {
770 return GD_FAILURE;
771 }
772
773 /* switch off colour merging on target gd image just while we write out
774 * content - we want to preserve the alpha data until the user chooses
775 * what to do with the image */
776 alphaBlendingFlag = im->alphaBlendingFlag;
777 gdImageAlphaBlending(im, 0);
778
779 success = TIFFReadRGBAImage(tif, width, height, buffer, 1);
780
781 if (success) {
782 for(y = 0; y < height; y++) {
783 for(x = 0; x < width; x++) {
784 /* if it doesn't already exist, allocate a new colour,
785 * else use existing one */
786 rgba = buffer[(y * width + x)];
787 a = (0xff - TIFFGetA(rgba)) / 2;
788 color = gdTrueColorAlpha(TIFFGetR(rgba), TIFFGetG(rgba), TIFFGetB(rgba), a);
789
790 /* set pixel colour to this colour */
791 gdImageSetPixel(im, x, height - y - 1, color);
792 }
793 }
794 }
795
796 gdFree(buffer);
797
798 /* now reset colour merge for alpha blending routines */
799 gdImageAlphaBlending(im, alphaBlendingFlag);
800 return success;
801 }
802
803 /*
804 Function: gdImageCreateFromTiffCtx
805
806 Create a gdImage from a TIFF file input from an gdIOCtx.
807 */
808 BGD_DECLARE(gdImagePtr) gdImageCreateFromTiffCtx(gdIOCtx *infile)
809 {
810 TIFF *tif;
811 tiff_handle *th;
812
813 uint16_t bps, spp, photometric;
814 uint16_t orientation;
815 int width, height;
816 uint16_t extra, *extra_types;
817 uint16_t planar;
818 char has_alpha, is_bw, is_gray;
819 char force_rgba = FALSE;
820 char save_transparent;
821 int image_type;
822 int ret;
823 float res_float;
824
825 gdImagePtr im = NULL;
826
827 th = new_tiff_handle(infile);
828 if (!th) {
829 return NULL;
830 }
831
832 tif = TIFFClientOpen("", "rb", th, tiff_readproc,
833 tiff_writeproc,
834 tiff_seekproc,
835 tiff_closeproc,
836 tiff_sizeproc,
837 tiff_mapproc,
838 tiff_unmapproc);
839
840 if (!tif) {
841 gd_error("Cannot open TIFF image");
842 gdFree(th);
843 return NULL;
844 }
845
846 if (!TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width)) {
847 gd_error("TIFF error, Cannot read image width");
848 goto error;
849 }
850
851 if (!TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height)) {
852 gd_error("TIFF error, Cannot read image width");
853 goto error;
854 }
855
856 TIFFGetFieldDefaulted (tif, TIFFTAG_BITSPERSAMPLE, &bps);
857
858 /* Unsupported bps, force to RGBA */
859 if (bps != 1 /*bps > 8 && bps != 16*/) {
860 force_rgba = TRUE;
861 }
862
863 TIFFGetFieldDefaulted (tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
864
865 if (!TIFFGetField (tif, TIFFTAG_EXTRASAMPLES, &extra, &extra_types)) {
866 extra = 0;
867 }
868
869 if (!TIFFGetField (tif, TIFFTAG_PHOTOMETRIC, &photometric)) {
870 uint16_t compression;
871 if (TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression) &&
872 (compression == COMPRESSION_CCITTFAX3 ||
873 compression == COMPRESSION_CCITTFAX4 ||
874 compression == COMPRESSION_CCITTRLE ||
875 compression == COMPRESSION_CCITTRLEW)) {
876 gd_error("Could not get photometric. "
877 "Image is CCITT compressed, assuming min-is-white");
878 photometric = PHOTOMETRIC_MINISWHITE;
879 } else {
880 gd_error("Could not get photometric. "
881 "Assuming min-is-black");
882
883 photometric = PHOTOMETRIC_MINISBLACK;
884 }
885 }
886 save_transparent = FALSE;
887
888 /* test if the extrasample represents an associated alpha channel... */
889 if (extra > 0 && (extra_types[0] == EXTRASAMPLE_ASSOCALPHA)) {
890 has_alpha = TRUE;
891 save_transparent = FALSE;
892 --extra;
893 } else if (extra > 0 && (extra_types[0] == EXTRASAMPLE_UNASSALPHA)) {
894 has_alpha = TRUE;
895 save_transparent = TRUE;
896 --extra;
897 } else if (extra > 0 && (extra_types[0] == EXTRASAMPLE_UNSPECIFIED)) {
898 /* assuming unassociated alpha if unspecified */
899 gd_error("alpha channel type not defined, assuming alpha is not premultiplied");
900 has_alpha = TRUE;
901 save_transparent = TRUE;
902 --extra;
903 } else {
904 has_alpha = FALSE;
905 }
906
907 if (photometric == PHOTOMETRIC_RGB && spp > 3 + extra) {
908 has_alpha = TRUE;
909 extra = spp - 4;
910 } else if (photometric != PHOTOMETRIC_RGB && spp > 1 + extra) {
911 has_alpha = TRUE;
912 extra = spp - 2;
913 }
914
915 is_bw = FALSE;
916 is_gray = FALSE;
917
918 switch (photometric) {
919 case PHOTOMETRIC_MINISBLACK:
920 case PHOTOMETRIC_MINISWHITE:
921 if (!has_alpha && bps == 1 && spp == 1) {
922 image_type = GD_INDEXED;
923 is_bw = TRUE;
924 } else {
925 image_type = GD_GRAY;
926 }
927 break;
928
929 case PHOTOMETRIC_RGB:
930 image_type = GD_RGB;
931 break;
932
933 case PHOTOMETRIC_PALETTE:
934 image_type = GD_INDEXED;
935 break;
936
937 default:
938 force_rgba = TRUE;
939 break;
940 }
941
942 /* Force rgba if image has 1bps, but is not bw */
943 if (bps == 1 && !is_bw) {
944 force_rgba = TRUE;
945 }
946
947 if (!TIFFGetField (tif, TIFFTAG_PLANARCONFIG, &planar)) {
948 planar = PLANARCONFIG_CONTIG;
949 }
950
951 /* Force rgba if image plans are not contiguous */
952 if (force_rgba || planar != PLANARCONFIG_CONTIG) {
953 image_type = GD_RGB;
954 }
955
956 if (!force_rgba &&
957 (image_type == GD_PALETTE || image_type == GD_INDEXED || image_type == GD_GRAY)) {
958 im = gdImageCreate(width, height);
959 if (!im) goto error;
960 readTiffColorMap(im, tif, is_bw, photometric);
961 } else {
962 im = gdImageCreateTrueColor(width, height);
963 if (!im) goto error;
964 }
965
966 #ifdef DEBUG
967 printf("force rgba: %i\n", force_rgba);
968 printf("has_alpha: %i\n", has_alpha);
969 printf("save trans: %i\n", save_transparent);
970 printf("is_bw: %i\n", is_bw);
971 printf("is_gray: %i\n", is_gray);
972 printf("type: %i\n", image_type);
973 #else
974 (void)is_gray;
975 (void)save_transparent;
976 #endif
977
978 if (force_rgba) {
979 ret = createFromTiffRgba(tif, im);
980 } else if (TIFFIsTiled(tif)) {
981 ret = createFromTiffTiles(tif, im, bps, photometric, has_alpha, is_bw, extra);
982 } else {
983 ret = createFromTiffLines(tif, im, bps, photometric, has_alpha, is_bw, extra);
984 }
985
986 if (!ret) {
987 gdImageDestroy(im);
988 im = NULL;
989 goto error;
990 }
991
992 if (TIFFGetField(tif, TIFFTAG_XRESOLUTION, &res_float)) {
993 im->res_x = (unsigned int)res_float; //truncate
994 }
995 if (TIFFGetField(tif, TIFFTAG_YRESOLUTION, &res_float)) {
996 im->res_y = (unsigned int)res_float; //truncate
997 }
998
999 if (TIFFGetField(tif, TIFFTAG_ORIENTATION, &orientation)) {
1000 switch (orientation) {
1001 case ORIENTATION_TOPLEFT:
1002 case ORIENTATION_TOPRIGHT:
1003 case ORIENTATION_BOTRIGHT:
1004 case ORIENTATION_BOTLEFT:
1005 break;
1006
1007 default:
1008 gd_error("Orientation %d not handled yet!", orientation);
1009 break;
1010 }
1011 }
1012 error:
1013 TIFFClose(tif);
1014 gdFree(th);
1015 return im;
1016 }
1017
1018 /*
1019 Function: gdImageCreateFromTIFF
1020 */
1021 BGD_DECLARE(gdImagePtr) gdImageCreateFromTiff(FILE *inFile)
1022 {
1023 gdImagePtr im;
1024 gdIOCtx *in = gdNewFileCtx(inFile);
1025 if (in == NULL) return NULL;
1026 im = gdImageCreateFromTiffCtx(in);
1027 in->gd_free(in);
1028 return im;
1029 }
1030
1031 /*
1032 Function: gdImageCreateFromTiffPtr
1033 */
1034 BGD_DECLARE(gdImagePtr) gdImageCreateFromTiffPtr(int size, void *data)
1035 {
1036 gdImagePtr im;
1037 gdIOCtx *in = gdNewDynamicCtxEx (size, data, 0);
1038 if (in == NULL) return NULL;
1039 im = gdImageCreateFromTiffCtx(in);
1040 in->gd_free(in);
1041 return im;
1042 }
1043
1044 /*
1045 Function: gdImageTiff
1046 */
1047 BGD_DECLARE(void) gdImageTiff(gdImagePtr im, FILE *outFile)
1048 {
1049 gdIOCtx *out = gdNewFileCtx(outFile);
1050 if (out == NULL) return;
1051 gdImageTiffCtx(im, out); /* what's an fg again? */
1052 out->gd_free(out);
1053 }
1054
1055 /*
1056 Function: gdImageTiffPtr
1057 */
1058 BGD_DECLARE(void *) gdImageTiffPtr(gdImagePtr im, int *size)
1059 {
1060 void *rv;
1061 gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
1062 if (out == NULL) return NULL;
1063 gdImageTiffCtx(im, out); /* what's an fg again? */
1064 rv = gdDPExtractData(out, size);
1065 out->gd_free(out);
1066 return rv;
1067 }
1068
1069 #else
1070
1071 static void _noTiffError(void)
1072 {
1073 gd_error("TIFF image support has been disabled\n");
1074 }
1075
1076 BGD_DECLARE(void) gdImageTiffCtx(gdImagePtr image, gdIOCtx *out)
1077 {
1078 ARG_NOT_USED(image);
1079 ARG_NOT_USED(out);
1080 _noTiffError();
1081 }
1082
1083 BGD_DECLARE(gdImagePtr) gdImageCreateFromTiffCtx(gdIOCtx *infile)
1084 {
1085 ARG_NOT_USED(infile);
1086 _noTiffError();
1087 return NULL;
1088 }
1089
1090 BGD_DECLARE(gdImagePtr) gdImageCreateFromTiff(FILE *inFile)
1091 {
1092 ARG_NOT_USED(inFile);
1093 _noTiffError();
1094 return NULL;
1095 }
1096
1097 BGD_DECLARE(gdImagePtr) gdImageCreateFromTiffPtr(int size, void *data)
1098 {
1099 ARG_NOT_USED(size);
1100 ARG_NOT_USED(data);
1101 _noTiffError();
1102 return NULL;
1103 }
1104
1105 BGD_DECLARE(void) gdImageTiff(gdImagePtr im, FILE *outFile)
1106 {
1107 ARG_NOT_USED(im);
1108 ARG_NOT_USED(outFile);
1109 _noTiffError();
1110 }
1111
1112 BGD_DECLARE(void *) gdImageTiffPtr(gdImagePtr im, int *size)
1113 {
1114 ARG_NOT_USED(im);
1115 ARG_NOT_USED(size);
1116 _noTiffError();
1117 return NULL;
1118 }
1119
1120 #endif