Blame src/gd_tiff.c

Packit Service df60bb
/*
Packit Service df60bb
   TIFF - Tagged Image File Format Encapsulation for GD Library
Packit Service df60bb
Packit Service df60bb
   gd_tiff.c
Packit Service df60bb
   Copyright (C) Pierre-A. Joye, M. Retallack
Packit Service df60bb
Packit Service df60bb
   ---------------------------------------------------------------------------
Packit Service df60bb
   **
Packit Service df60bb
   ** Permission to use, copy, modify, and distribute this software and its
Packit Service df60bb
   ** documentation for any purpose and without fee is hereby granted, provided
Packit Service df60bb
   ** that the above copyright notice appear in all copies and that both that
Packit Service df60bb
   ** copyright notice and this permission notice appear in supporting
Packit Service df60bb
   ** documentation.  This software is provided "as is" without express or
Packit Service df60bb
   ** implied warranty.
Packit Service df60bb
   **
Packit Service df60bb
   ---------------------------------------------------------------------------
Packit Service df60bb
   Ctx code written by M. Retallack
Packit Service df60bb
Packit Service df60bb
   Todo:
Packit Service df60bb
Packit Service df60bb
   If we fail - cleanup
Packit Service df60bb
   Writer: Use gd error function, overflow check may not be necessary as
Packit Service df60bb
	 we write our own data (check already done)
Packit Service df60bb
Packit Service df60bb
   Implement 2 color black/white saving using group4 fax compression
Packit Service df60bb
   Implement function to specify encoding to use when writing tiff data
Packit Service df60bb
Packit Service df60bb
   ----------------------------------------------------------------------------
Packit Service df60bb
 */
Packit Service df60bb
/* $Id$ */
Packit Service df60bb
Packit Service df60bb
/**
Packit Service df60bb
 * File: TIFF IO
Packit Service df60bb
 *
Packit Service df60bb
 * Read and write TIFF images.
Packit Service df60bb
 *
Packit Service df60bb
 * There is only most basic support for the TIFF format available for now;
Packit Service df60bb
 * for instance, multiple pages are not yet supported.
Packit Service df60bb
 */
Packit Service df60bb
Packit Service df60bb
#ifdef HAVE_CONFIG_H
Packit Service df60bb
#	include "config.h"
Packit Service df60bb
#endif
Packit Service df60bb
Packit Service df60bb
#include "gd.h"
Packit Service df60bb
#include "gd_errors.h"
Packit Service df60bb
#include "gdfonts.h"
Packit Service df60bb
#include <stdio.h>
Packit Service df60bb
#include <stdlib.h>
Packit Service df60bb
#include <limits.h>
Packit Service df60bb
Packit Service df60bb
#include "gdhelpers.h"
Packit Service df60bb
Packit Service df60bb
#ifdef HAVE_LIBTIFF
Packit Service df60bb
Packit Service df60bb
#include "tiff.h"
Packit Service df60bb
#include "tiffio.h"
Packit Service df60bb
Packit Service df60bb
#define GD_SUCCESS 1
Packit Service df60bb
#define GD_FAILURE 0
Packit Service df60bb
Packit Service df60bb
#define TRUE 1
Packit Service df60bb
#define FALSE 0
Packit Service df60bb
Packit Service df60bb
/* I define those here until the new formats
Packit Service df60bb
 * are commited. We can then rely on the global
Packit Service df60bb
 * def
Packit Service df60bb
 */
Packit Service df60bb
#define GD_PALETTE 1
Packit Service df60bb
#define GD_TRUECOLOR 2
Packit Service df60bb
#define GD_GRAY 3
Packit Service df60bb
#define GD_INDEXED 4
Packit Service df60bb
#define GD_RGB 5
Packit Service df60bb
Packit Service df60bb
#define MIN(a,b) (a < b) ? a : b;
Packit Service df60bb
#define MAX(a,b) (a > b) ? a : b;
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
typedef struct tiff_handle {
Packit Service df60bb
	int size;
Packit Service df60bb
	int pos;
Packit Service df60bb
	gdIOCtx *ctx;
Packit Service df60bb
	int written;
Packit Service df60bb
}
Packit Service df60bb
tiff_handle;
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
   Functions for reading, writing and seeking in gdIOCtx
Packit Service df60bb
   This allows for non-file i/o operations with no
Packit Service df60bb
   explicit use of libtiff fileio wrapper functions
Packit Service df60bb
Packit Service df60bb
   Note: because libtiff requires random access, but gdIOCtx
Packit Service df60bb
         only supports streams, all writes are buffered
Packit Service df60bb
         into memory and written out on close, also all
Packit Service df60bb
         reads are done from a memory mapped version of the
Packit Service df60bb
         tiff (assuming one already exists)
Packit Service df60bb
*/
Packit Service df60bb
Packit Service df60bb
tiff_handle * new_tiff_handle(gdIOCtx *g)
Packit Service df60bb
{
Packit Service df60bb
	tiff_handle * t;
Packit Service df60bb
Packit Service df60bb
	if (!g) {
Packit Service df60bb
		gd_error("Cannot create a new tiff handle, missing Ctx argument");
Packit Service df60bb
		return NULL;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	t = (tiff_handle *) gdMalloc(sizeof(tiff_handle));
Packit Service df60bb
	if (!t) {
Packit Service df60bb
		gd_error("Failed to allocate a new tiff handle");
Packit Service df60bb
		return NULL;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	t->size = 0;
Packit Service df60bb
	t->pos = 0;
Packit Service df60bb
	t->ctx = g;
Packit Service df60bb
	t->written = 0;
Packit Service df60bb
Packit Service df60bb
	return t;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/* TIFFReadWriteProc tiff_readproc - Will use gdIOCtx procs to read required
Packit Service df60bb
   (previously written) TIFF file content */
Packit Service df60bb
static tsize_t tiff_readproc(thandle_t clientdata, tdata_t data, tsize_t size)
Packit Service df60bb
{
Packit Service df60bb
	tiff_handle *th = (tiff_handle *)clientdata;
Packit Service df60bb
	gdIOCtx *ctx = th->ctx;
Packit Service df60bb
Packit Service df60bb
	size = (ctx->getBuf)(ctx, data, size);
Packit Service df60bb
Packit Service df60bb
	return size;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/* TIFFReadWriteProc tiff_writeproc - Will use gdIOCtx procs to write out
Packit Service df60bb
   TIFF data */
Packit Service df60bb
static tsize_t tiff_writeproc(thandle_t clientdata, tdata_t data, tsize_t size)
Packit Service df60bb
{
Packit Service df60bb
	tiff_handle *th = (tiff_handle *)clientdata;
Packit Service df60bb
	gdIOCtx *ctx = th->ctx;
Packit Service df60bb
Packit Service df60bb
	size = (ctx->putBuf)(ctx, data, size);
Packit Service df60bb
	if(size + th->pos>th->size) {
Packit Service df60bb
		th->size = size + th->pos;
Packit Service df60bb
		th->pos += size;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	return size;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/* TIFFSeekProc tiff_seekproc
Packit Service df60bb
 * used to move around the partially written TIFF */
Packit Service df60bb
static toff_t tiff_seekproc(thandle_t clientdata, toff_t offset, int from)
Packit Service df60bb
{
Packit Service df60bb
	tiff_handle *th = (tiff_handle *)clientdata;
Packit Service df60bb
	gdIOCtx *ctx = th->ctx;
Packit Service df60bb
	int result;
Packit Service df60bb
Packit Service df60bb
	switch(from) {
Packit Service df60bb
	default:
Packit Service df60bb
	case SEEK_SET:
Packit Service df60bb
		/* just use offset */
Packit Service df60bb
		break;
Packit Service df60bb
Packit Service df60bb
	case SEEK_END:
Packit Service df60bb
		/* invert offset, so that it is from start, not end as supplied */
Packit Service df60bb
		offset = th->size + offset;
Packit Service df60bb
		break;
Packit Service df60bb
Packit Service df60bb
	case SEEK_CUR:
Packit Service df60bb
		/* add current position to translate it to 'from start',
Packit Service df60bb
		 * not from durrent as supplied
Packit Service df60bb
		 */
Packit Service df60bb
		offset += th->pos;
Packit Service df60bb
		break;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* now, move pos in both io context and buf */
Packit Service df60bb
	if((result = (ctx->seek)(ctx, offset))) {
Packit Service df60bb
		th->pos = offset;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	return result ? offset : (toff_t)-1;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/* TIFFCloseProc tiff_closeproc - used to finally close the TIFF file */
Packit Service df60bb
static int tiff_closeproc(thandle_t clientdata)
Packit Service df60bb
{
Packit Service df60bb
	(void)clientdata;
Packit Service df60bb
	/*tiff_handle *th = (tiff_handle *)clientdata;
Packit Service df60bb
	gdIOCtx *ctx = th->ctx;
Packit Service df60bb
Packit Service df60bb
	(ctx->gd_free)(ctx);*/
Packit Service df60bb
Packit Service df60bb
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/* TIFFSizeProc tiff_sizeproc */
Packit Service df60bb
static toff_t tiff_sizeproc(thandle_t clientdata)
Packit Service df60bb
{
Packit Service df60bb
	tiff_handle *th = (tiff_handle *)clientdata;
Packit Service df60bb
	return th->size;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/* TIFFMapFileProc tiff_mapproc() */
Packit Service df60bb
static int tiff_mapproc(thandle_t h, tdata_t *d, toff_t *o)
Packit Service df60bb
{
Packit Service df60bb
	(void)h;
Packit Service df60bb
	(void)d;
Packit Service df60bb
	(void)o;
Packit Service df60bb
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/* TIFFUnmapFileProc tiff_unmapproc */
Packit Service df60bb
static void tiff_unmapproc(thandle_t h, tdata_t d, toff_t o)
Packit Service df60bb
{
Packit Service df60bb
	(void)h;
Packit Service df60bb
	(void)d;
Packit Service df60bb
	(void)o;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
/*  tiffWriter
Packit Service df60bb
 *  ----------
Packit Service df60bb
 *  Write the gd image as a tiff file (called by gdImageTiffCtx)
Packit Service df60bb
 *  Parameters are:
Packit Service df60bb
 *  image:    gd image structure;
Packit Service df60bb
 *  out:      the stream where to write
Packit Service df60bb
 *  bitDepth: depth in bits of each pixel
Packit Service df60bb
 */
Packit Service df60bb
void tiffWriter(gdImagePtr image, gdIOCtx *out, int bitDepth)
Packit Service df60bb
{
Packit Service df60bb
	int x, y;
Packit Service df60bb
	int i;
Packit Service df60bb
	int r, g, b, a;
Packit Service df60bb
	TIFF *tiff;
Packit Service df60bb
	int width, height;
Packit Service df60bb
	int color;
Packit Service df60bb
	char *scan;
Packit Service df60bb
	int samplesPerPixel = 3;
Packit Service df60bb
	int bitsPerSample;
Packit Service df60bb
	int transparentColorR = -1;
Packit Service df60bb
	int transparentColorG = -1;
Packit Service df60bb
	int transparentColorB = -1;
Packit Service df60bb
	uint16 extraSamples[1];
Packit Service df60bb
	uint16 *colorMapRed = NULL;
Packit Service df60bb
	uint16 *colorMapGreen = NULL;
Packit Service df60bb
	uint16 *colorMapBlue = NULL;
Packit Service df60bb
Packit Service df60bb
	tiff_handle *th;
Packit Service df60bb
Packit Service df60bb
	th = new_tiff_handle(out);
Packit Service df60bb
	if (!th) {
Packit Service df60bb
		return;
Packit Service df60bb
	}
Packit Service df60bb
	extraSamples[0] = EXTRASAMPLE_ASSOCALPHA;
Packit Service df60bb
Packit Service df60bb
	/* read in the width/height of gd image */
Packit Service df60bb
	width = gdImageSX(image);
Packit Service df60bb
	height = gdImageSY(image);
Packit Service df60bb
Packit Service df60bb
	/* reset clip region to whole image */
Packit Service df60bb
	gdImageSetClip(image, 0, 0, width, height);
Packit Service df60bb
Packit Service df60bb
	/* handle old-style single-colour mapping to 100% transparency */
Packit Service df60bb
	if(image->transparent != -1) {
Packit Service df60bb
		/* set our 100% transparent colour value */
Packit Service df60bb
		transparentColorR = gdImageRed(image, image->transparent);
Packit Service df60bb
		transparentColorG = gdImageGreen(image, image->transparent);
Packit Service df60bb
		transparentColorB = gdImageBlue(image, image->transparent);
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* Open tiff file writing routines, but use special read/write/seek
Packit Service df60bb
	 * functions so that tiff lib writes correct bits of tiff content to
Packit Service df60bb
	 * correct areas of file opened and modifieable by the gdIOCtx functions
Packit Service df60bb
	 */
Packit Service df60bb
	tiff = TIFFClientOpen("", "w", th,	tiff_readproc,
Packit Service df60bb
			      tiff_writeproc,
Packit Service df60bb
			      tiff_seekproc,
Packit Service df60bb
			      tiff_closeproc,
Packit Service df60bb
			      tiff_sizeproc,
Packit Service df60bb
			      tiff_mapproc,
Packit Service df60bb
			      tiff_unmapproc);
Packit Service df60bb
Packit Service df60bb
	TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, width);
Packit Service df60bb
	TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, height);
Packit Service df60bb
	TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
Packit Service df60bb
	TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
Packit Service df60bb
	TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC,
Packit Service df60bb
		     (bitDepth == 24) ? PHOTOMETRIC_RGB : PHOTOMETRIC_PALETTE);
Packit Service df60bb
Packit Service df60bb
	bitsPerSample = (bitDepth == 24 || bitDepth == 8) ? 8 : 1;
Packit Service df60bb
	TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, bitsPerSample);
Packit Service df60bb
Packit Service df60bb
	TIFFSetField(tiff, TIFFTAG_XRESOLUTION, (float)image->res_x);
Packit Service df60bb
	TIFFSetField(tiff, TIFFTAG_YRESOLUTION, (float)image->res_y);
Packit Service df60bb
Packit Service df60bb
	/* build the color map for 8 bit images */
Packit Service df60bb
	if(bitDepth != 24) {
Packit Service df60bb
		colorMapRed   = (uint16 *) gdMalloc(3 * (1 << bitsPerSample));
Packit Service df60bb
		if (!colorMapRed) {
Packit Service df60bb
			gdFree(th);
Packit Service df60bb
			return;
Packit Service df60bb
		}
Packit Service df60bb
		colorMapGreen = (uint16 *) gdMalloc(3 * (1 << bitsPerSample));
Packit Service df60bb
		if (!colorMapGreen) {
Packit Service df60bb
			gdFree(colorMapRed);
Packit Service df60bb
			gdFree(th);
Packit Service df60bb
			return;
Packit Service df60bb
		}
Packit Service df60bb
		colorMapBlue  = (uint16 *) gdMalloc(3 *  (1 << bitsPerSample));
Packit Service df60bb
		if (!colorMapBlue) {
Packit Service df60bb
			gdFree(colorMapRed);
Packit Service df60bb
			gdFree(colorMapGreen);
Packit Service df60bb
			gdFree(th);
Packit Service df60bb
			return;
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		for(i = 0; i < image->colorsTotal; i++) {
Packit Service df60bb
			colorMapRed[i]   = gdImageRed(image,i) + (gdImageRed(image,i) * 256);
Packit Service df60bb
			colorMapGreen[i] = gdImageGreen(image,i)+(gdImageGreen(image,i)*256);
Packit Service df60bb
			colorMapBlue[i]  = gdImageBlue(image,i) + (gdImageBlue(image,i)*256);
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		TIFFSetField(tiff, TIFFTAG_COLORMAP, colorMapRed, colorMapGreen,
Packit Service df60bb
			     colorMapBlue);
Packit Service df60bb
		samplesPerPixel = 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* here, we check if the 'save alpha' flag is set on the source gd image */
Packit Service df60bb
	if ((bitDepth == 24) &&
Packit Service df60bb
	    (image->saveAlphaFlag || image->transparent != -1)) {
Packit Service df60bb
		/* so, we need to store the alpha values too!
Packit Service df60bb
		 * Also, tell TIFF what the extra sample means (associated alpha) */
Packit Service df60bb
		samplesPerPixel = 4;
Packit Service df60bb
		TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, samplesPerPixel);
Packit Service df60bb
		TIFFSetField(tiff, TIFFTAG_EXTRASAMPLES, 1, extraSamples);
Packit Service df60bb
	} else {
Packit Service df60bb
		TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, samplesPerPixel);
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	TIFFSetField(tiff, TIFFTAG_ROWSPERSTRIP, 1);
Packit Service df60bb
Packit Service df60bb
	if(overflow2(width, samplesPerPixel)) {
Packit Service df60bb
		if (colorMapRed)   gdFree(colorMapRed);
Packit Service df60bb
		if (colorMapGreen) gdFree(colorMapGreen);
Packit Service df60bb
		if (colorMapBlue)  gdFree(colorMapBlue);
Packit Service df60bb
		gdFree(th);
Packit Service df60bb
		return;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if(!(scan = (char *)gdMalloc(width * samplesPerPixel))) {
Packit Service df60bb
		if (colorMapRed)   gdFree(colorMapRed);
Packit Service df60bb
		if (colorMapGreen) gdFree(colorMapGreen);
Packit Service df60bb
		if (colorMapBlue)  gdFree(colorMapBlue);
Packit Service df60bb
		gdFree(th);
Packit Service df60bb
		return;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* loop through y-coords, and x-coords */
Packit Service df60bb
	for(y = 0; y < height; y++) {
Packit Service df60bb
		for(x = 0; x < width; x++) {
Packit Service df60bb
			/* generate scan line for writing to tiff */
Packit Service df60bb
			color = gdImageGetPixel(image, x, y);
Packit Service df60bb
Packit Service df60bb
			a = (127 - gdImageAlpha(image, color)) * 2;
Packit Service df60bb
			a = (a == 0xfe) ? 0xff : a & 0xff;
Packit Service df60bb
			b = gdImageBlue(image, color);
Packit Service df60bb
			g = gdImageGreen(image, color);
Packit Service df60bb
			r = gdImageRed(image, color);
Packit Service df60bb
Packit Service df60bb
			/* if this pixel has the same RGB as the transparent colour,
Packit Service df60bb
			 * then set alpha fully transparent */
Packit Service df60bb
			if (transparentColorR == r &&
Packit Service df60bb
			    transparentColorG == g &&
Packit Service df60bb
			    transparentColorB == b) {
Packit Service df60bb
				a = 0x00;
Packit Service df60bb
			}
Packit Service df60bb
Packit Service df60bb
			if(bitDepth != 24) {
Packit Service df60bb
				/* write out 1 or 8 bit value in 1 byte
Packit Service df60bb
				 * (currently treats 1bit as 8bit) */
Packit Service df60bb
				scan[(x * samplesPerPixel) + 0] = color;
Packit Service df60bb
			} else {
Packit Service df60bb
				/* write out 24 bit value in 3 (or 4 if transparent) bytes */
Packit Service df60bb
				if(image->saveAlphaFlag || image->transparent != -1) {
Packit Service df60bb
					scan[(x * samplesPerPixel) + 3] = a;
Packit Service df60bb
				}
Packit Service df60bb
Packit Service df60bb
				scan[(x * samplesPerPixel) + 2] = b;
Packit Service df60bb
				scan[(x * samplesPerPixel) + 1] = g;
Packit Service df60bb
				scan[(x * samplesPerPixel) + 0] = r;
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		/* Write the scan line to the tiff */
Packit Service df60bb
		if(TIFFWriteEncodedStrip(tiff, y, scan, width * samplesPerPixel) == -1) {
Packit Service df60bb
			if (colorMapRed)   gdFree(colorMapRed);
Packit Service df60bb
			if (colorMapGreen) gdFree(colorMapGreen);
Packit Service df60bb
			if (colorMapBlue)  gdFree(colorMapBlue);
Packit Service df60bb
			gdFree(th);
Packit Service df60bb
			/* error handler here */
Packit Service df60bb
			gd_error("Could not create TIFF\n");
Packit Service df60bb
			return;
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* now cloase and free up resources */
Packit Service df60bb
	TIFFClose(tiff);
Packit Service df60bb
	gdFree(scan);
Packit Service df60bb
	gdFree(th);
Packit Service df60bb
Packit Service df60bb
	if(bitDepth != 24) {
Packit Service df60bb
		gdFree(colorMapRed);
Packit Service df60bb
		gdFree(colorMapGreen);
Packit Service df60bb
		gdFree(colorMapBlue);
Packit Service df60bb
	}
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
	Function: gdImageTiffCtx
Packit Service df60bb
Packit Service df60bb
	Write the gd image as a tiff file.
Packit Service df60bb
Packit Service df60bb
	Parameters:
Packit Service df60bb
Packit Service df60bb
		image - gd image structure;
Packit Service df60bb
		out   - the stream where to write
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(void) gdImageTiffCtx(gdImagePtr image, gdIOCtx *out)
Packit Service df60bb
{
Packit Service df60bb
	int clipx1P, clipy1P, clipx2P, clipy2P;
Packit Service df60bb
	int bitDepth = 24;
Packit Service df60bb
Packit Service df60bb
	/* First, switch off clipping, or we'll not get all the image! */
Packit Service df60bb
	gdImageGetClip(image, &clipx1P, &clipy1P, &clipx2P, &clipy2P);
Packit Service df60bb
Packit Service df60bb
	/* use the appropriate routine depending on the bit depth of the image */
Packit Service df60bb
	if(image->trueColor) {
Packit Service df60bb
		bitDepth = 24;
Packit Service df60bb
	} else if(image->colorsTotal == 2) {
Packit Service df60bb
		bitDepth = 1;
Packit Service df60bb
	} else {
Packit Service df60bb
		bitDepth = 8;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	tiffWriter(image, out, bitDepth);
Packit Service df60bb
Packit Service df60bb
	/* reset clipping area to the gd image's original values */
Packit Service df60bb
	gdImageSetClip(image, clipx1P, clipy1P, clipx2P, clipy2P);
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/* Check if we are really in 8bit mode */
Packit Service df60bb
static int checkColorMap(n, r, g, b)
Packit Service df60bb
int n;
Packit Service df60bb
uint16 *r, *g, *b;
Packit Service df60bb
{
Packit Service df60bb
	while (n-- > 0)
Packit Service df60bb
		if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256)
Packit Service df60bb
			return (16);
Packit Service df60bb
	return (8);
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
/* Read and convert a TIFF colormap */
Packit Service df60bb
static int readTiffColorMap(gdImagePtr im, TIFF *tif, char is_bw, int photometric)
Packit Service df60bb
{
Packit Service df60bb
	uint16 *redcmap, *greencmap, *bluecmap;
Packit Service df60bb
	uint16 bps;
Packit Service df60bb
	int i;
Packit Service df60bb
Packit Service df60bb
	if (is_bw) {
Packit Service df60bb
		if (photometric == PHOTOMETRIC_MINISWHITE) {
Packit Service df60bb
			gdImageColorAllocate(im, 255,255,255);
Packit Service df60bb
			gdImageColorAllocate(im, 0, 0, 0);
Packit Service df60bb
		} else {
Packit Service df60bb
			gdImageColorAllocate(im, 0, 0, 0);
Packit Service df60bb
			gdImageColorAllocate(im, 255,255,255);
Packit Service df60bb
		}
Packit Service df60bb
	} else {
Packit Service df60bb
		uint16 min_sample_val, max_sample_val;
Packit Service df60bb
Packit Service df60bb
		if (!TIFFGetField(tif, TIFFTAG_MINSAMPLEVALUE, &min_sample_val)) {
Packit Service df60bb
			min_sample_val = 0;
Packit Service df60bb
		}
Packit Service df60bb
		if (!TIFFGetField(tif, TIFFTAG_MAXSAMPLEVALUE, &max_sample_val)) {
Packit Service df60bb
			max_sample_val = 255;
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		if (photometric == PHOTOMETRIC_MINISBLACK || photometric == PHOTOMETRIC_MINISWHITE) {
Packit Service df60bb
			/* TODO: use TIFFTAG_MINSAMPLEVALUE and TIFFTAG_MAXSAMPLEVALUE */
Packit Service df60bb
			/* Gray level palette */
Packit Service df60bb
			for (i=min_sample_val; i <= max_sample_val; i++) {
Packit Service df60bb
				gdImageColorAllocate(im, i,i,i);
Packit Service df60bb
			}
Packit Service df60bb
			return GD_SUCCESS;
Packit Service df60bb
Packit Service df60bb
		} else if (!TIFFGetField(tif, TIFFTAG_COLORMAP, &redcmap, &greencmap, &bluecmap)) {
Packit Service df60bb
			gd_error("Cannot read the color map");
Packit Service df60bb
			return GD_FAILURE;
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bps;;
Packit Service df60bb
Packit Service df60bb
#define	CVT(x)		(((x) * 255) / ((1L<<16)-1))
Packit Service df60bb
		if (checkColorMap(1<
Packit Service df60bb
			for (i = (1<<bps)-1; i > 0; i--) {
Packit Service df60bb
				redcmap[i] = CVT(redcmap[i]);
Packit Service df60bb
				greencmap[i] = CVT(greencmap[i]);
Packit Service df60bb
				bluecmap[i] = CVT(bluecmap[i]);
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
		for (i = 0; i < 256; i++) {
Packit Service df60bb
			gdImageColorAllocate(im, redcmap[i], greencmap[i], bluecmap[i]);
Packit Service df60bb
		}
Packit Service df60bb
#undef CVT
Packit Service df60bb
	}
Packit Service df60bb
	return GD_SUCCESS;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static void readTiffBw (const unsigned char *src,
Packit Service df60bb
			gdImagePtr im,
Packit Service df60bb
			uint16       photometric,
Packit Service df60bb
			int          startx,
Packit Service df60bb
			int          starty,
Packit Service df60bb
			int          width,
Packit Service df60bb
			int          height,
Packit Service df60bb
			char         has_alpha,
Packit Service df60bb
			int          extra,
Packit Service df60bb
			int          align)
Packit Service df60bb
{
Packit Service df60bb
	int x = startx, y = starty;
Packit Service df60bb
Packit Service df60bb
	(void)has_alpha;
Packit Service df60bb
	(void)extra;
Packit Service df60bb
	(void)align;
Packit Service df60bb
Packit Service df60bb
	for (y = starty; y < starty + height; y++) {
Packit Service df60bb
		for (x = startx; x < startx + width;) {
Packit Service df60bb
			register unsigned char curr = *src++;
Packit Service df60bb
			register unsigned char mask;
Packit Service df60bb
Packit Service df60bb
			if (photometric == PHOTOMETRIC_MINISWHITE) {
Packit Service df60bb
				curr = ~curr;
Packit Service df60bb
			}
Packit Service df60bb
			for (mask = 0x80; mask != 0 && x < startx + width; x++, mask >>= 1) {
Packit Service df60bb
				gdImageSetPixel(im, x, y, ((curr & mask) != 0)?0:1);
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static void readTiff8bit (const unsigned char *src,
Packit Service df60bb
                          gdImagePtr im,
Packit Service df60bb
                          uint16       photometric,
Packit Service df60bb
                          int          startx,
Packit Service df60bb
                          int          starty,
Packit Service df60bb
                          int          width,
Packit Service df60bb
                          int          height,
Packit Service df60bb
                          char         has_alpha,
Packit Service df60bb
                          int          extra,
Packit Service df60bb
                          int          align)
Packit Service df60bb
{
Packit Service df60bb
	int    red, green, blue, alpha;
Packit Service df60bb
	int    x, y;
Packit Service df60bb
Packit Service df60bb
	(void)extra;
Packit Service df60bb
	(void)align;
Packit Service df60bb
Packit Service df60bb
	switch (photometric) {
Packit Service df60bb
	case PHOTOMETRIC_PALETTE:
Packit Service df60bb
		/* Palette has no alpha (see TIFF specs for more details */
Packit Service df60bb
		for (y = starty; y < starty + height; y++) {
Packit Service df60bb
			for (x = startx; x < startx + width; x++) {
Packit Service df60bb
				gdImageSetPixel(im, x, y,*(src++));
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
		break;
Packit Service df60bb
Packit Service df60bb
	case PHOTOMETRIC_RGB:
Packit Service df60bb
		if (has_alpha) {
Packit Service df60bb
			gdImageAlphaBlending(im, 0);
Packit Service df60bb
			gdImageSaveAlpha(im, 1);
Packit Service df60bb
Packit Service df60bb
			for (y = starty; y < starty + height; y++) {
Packit Service df60bb
				for (x = startx; x < startx + width; x++) {
Packit Service df60bb
					red   = *src++;
Packit Service df60bb
					green = *src++;
Packit Service df60bb
					blue  = *src++;
Packit Service df60bb
					alpha = *src++;
Packit Service df60bb
					red   = MIN (red, alpha);
Packit Service df60bb
					blue  = MIN (blue, alpha);
Packit Service df60bb
					green = MIN (green, alpha);
Packit Service df60bb
Packit Service df60bb
					if (alpha) {
Packit Service df60bb
						gdImageSetPixel(im, x, y, gdTrueColorAlpha(red * 255 / alpha, green * 255 / alpha, blue * 255 /alpha, gdAlphaMax - (alpha >> 1)));
Packit Service df60bb
					} else {
Packit Service df60bb
						gdImageSetPixel(im, x, y, gdTrueColorAlpha(red, green, blue, gdAlphaMax - (alpha >> 1)));
Packit Service df60bb
					}
Packit Service df60bb
				}
Packit Service df60bb
			}
Packit Service df60bb
Packit Service df60bb
		} else {
Packit Service df60bb
			for (y = 0; y < height; y++) {
Packit Service df60bb
				for (x = 0; x < width; x++) {
Packit Service df60bb
					register unsigned char r = *src++;
Packit Service df60bb
					register unsigned char g = *src++;
Packit Service df60bb
					register unsigned char b = *src++;
Packit Service df60bb
Packit Service df60bb
					gdImageSetPixel(im, x, y, gdTrueColor(r, g, b));
Packit Service df60bb
				}
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
		break;
Packit Service df60bb
Packit Service df60bb
	case PHOTOMETRIC_MINISWHITE:
Packit Service df60bb
		if (has_alpha) {
Packit Service df60bb
			/* We don't process the extra yet */
Packit Service df60bb
		} else {
Packit Service df60bb
			for (y = starty; y < starty + height; y++) {
Packit Service df60bb
				for (x = startx; x < startx + width; x++) {
Packit Service df60bb
					gdImageSetPixel(im, x, y, ~(*src++));
Packit Service df60bb
				}
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
		break;
Packit Service df60bb
Packit Service df60bb
	case PHOTOMETRIC_MINISBLACK:
Packit Service df60bb
		if (has_alpha) {
Packit Service df60bb
			/* We don't process the extra yet */
Packit Service df60bb
		} else {
Packit Service df60bb
			for (y = starty; y < height; y++) {
Packit Service df60bb
				for (x = 0; x < width; x++) {
Packit Service df60bb
					gdImageSetPixel(im, x, y, *src++);
Packit Service df60bb
				}
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
		break;
Packit Service df60bb
	}
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static int createFromTiffTiles(TIFF *tif, gdImagePtr im, uint16 bps, uint16 photometric,
Packit Service df60bb
                               char has_alpha, char is_bw, int extra)
Packit Service df60bb
{
Packit Service df60bb
	uint16  planar;
Packit Service df60bb
	int im_width, im_height;
Packit Service df60bb
	int tile_width, tile_height;
Packit Service df60bb
	int  x, y, height, width;
Packit Service df60bb
	unsigned char *buffer;
Packit Service df60bb
	int success = GD_SUCCESS;
Packit Service df60bb
Packit Service df60bb
	if (!TIFFGetField (tif, TIFFTAG_PLANARCONFIG, &planar)) {
Packit Service df60bb
		planar = PLANARCONFIG_CONTIG;
Packit Service df60bb
	}
Packit Service df60bb
	if (TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &im_width) == 0 ||
Packit Service df60bb
		TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &im_height) == 0 ||
Packit Service df60bb
		TIFFGetField (tif, TIFFTAG_TILEWIDTH, &tile_width) ==  0 ||
Packit Service df60bb
		TIFFGetField (tif, TIFFTAG_TILELENGTH, &tile_height) == 0) {
Packit Service df60bb
		return FALSE;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	buffer = (unsigned char *) gdMalloc (TIFFTileSize (tif));
Packit Service df60bb
	if (!buffer) {
Packit Service df60bb
		return FALSE;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	for (y = 0; y < im_height; y += tile_height) {
Packit Service df60bb
		for (x = 0; x < im_width; x += tile_width) {
Packit Service df60bb
			if (TIFFReadTile(tif, buffer, x, y, 0, 0) < 0) {
Packit Service df60bb
				success = GD_FAILURE;
Packit Service df60bb
				goto end;
Packit Service df60bb
			}
Packit Service df60bb
			width = MIN(im_width - x, tile_width);
Packit Service df60bb
			height = MIN(im_height - y, tile_height);
Packit Service df60bb
			if (bps == 16) {
Packit Service df60bb
			} else if (bps == 8) {
Packit Service df60bb
				readTiff8bit(buffer, im, photometric, x, y, width, height, has_alpha, extra, 0);
Packit Service df60bb
			} else if (is_bw) {
Packit Service df60bb
				readTiffBw(buffer, im, photometric, x, y, width, height, has_alpha, extra, 0);
Packit Service df60bb
			} else {
Packit Service df60bb
				/* TODO: implement some default reader or detect this case earlier use force_rgb */
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
end:
Packit Service df60bb
	gdFree(buffer);
Packit Service df60bb
	return success;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static int createFromTiffLines(TIFF *tif, gdImagePtr im, uint16 bps, uint16 photometric,
Packit Service df60bb
                               char has_alpha, char is_bw, int extra)
Packit Service df60bb
{
Packit Service df60bb
	uint16  planar;
Packit Service df60bb
	uint32 im_height, im_width, y;
Packit Service df60bb
Packit Service df60bb
	unsigned char *buffer;
Packit Service df60bb
	int success = GD_SUCCESS;
Packit Service df60bb
Packit Service df60bb
	if (!TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planar)) {
Packit Service df60bb
		planar = PLANARCONFIG_CONTIG;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (!TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &im_height)) {
Packit Service df60bb
		gd_error("Can't fetch TIFF height\n");
Packit Service df60bb
		return FALSE;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (!TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &im_width)) {
Packit Service df60bb
		gd_error("Can't fetch TIFF width \n");
Packit Service df60bb
		return FALSE;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	buffer = (unsigned char *)gdMalloc(im_width * 4);
Packit Service df60bb
	if (!buffer) {
Packit Service df60bb
		return GD_FAILURE;
Packit Service df60bb
	}
Packit Service df60bb
	if (planar == PLANARCONFIG_CONTIG) {
Packit Service df60bb
		switch (bps) {
Packit Service df60bb
		case 16:
Packit Service df60bb
			/* TODO
Packit Service df60bb
			 * or simply use force_rgba
Packit Service df60bb
			 */
Packit Service df60bb
			break;
Packit Service df60bb
Packit Service df60bb
		case 8:
Packit Service df60bb
			for (y = 0; y < im_height; y++ ) {
Packit Service df60bb
				if (TIFFReadScanline (tif, buffer, y, 0) < 0) {
Packit Service df60bb
					gd_error("Error while reading scanline %i", y);
Packit Service df60bb
					success = GD_FAILURE;
Packit Service df60bb
					break;
Packit Service df60bb
				}
Packit Service df60bb
				/* reading one line at a time */
Packit Service df60bb
				readTiff8bit(buffer, im, photometric, 0, y, im_width, 1, has_alpha, extra, 0);
Packit Service df60bb
			}
Packit Service df60bb
			break;
Packit Service df60bb
Packit Service df60bb
		default:
Packit Service df60bb
			if (is_bw) {
Packit Service df60bb
				for (y = 0; y < im_height; y++ ) {
Packit Service df60bb
					if (TIFFReadScanline (tif, buffer, y, 0) < 0) {
Packit Service df60bb
						gd_error("Error while reading scanline %i", y);
Packit Service df60bb
						success = GD_FAILURE;
Packit Service df60bb
						break;
Packit Service df60bb
					}
Packit Service df60bb
					/* reading one line at a time */
Packit Service df60bb
					readTiffBw(buffer, im, photometric, 0, y, im_width, 1, has_alpha, extra, 0);
Packit Service df60bb
				}
Packit Service df60bb
			} else {
Packit Service df60bb
				/* TODO: implement some default reader or detect this case earlier > force_rgb */
Packit Service df60bb
			}
Packit Service df60bb
			break;
Packit Service df60bb
		}
Packit Service df60bb
	} else {
Packit Service df60bb
		/* TODO: implement a reader for separate panes. We detect this case earlier for now and use force_rgb */
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	gdFree(buffer);
Packit Service df60bb
	return success;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static int createFromTiffRgba(TIFF * tif, gdImagePtr im)
Packit Service df60bb
{
Packit Service df60bb
	int a;
Packit Service df60bb
	int x, y;
Packit Service df60bb
	int alphaBlendingFlag = 0;
Packit Service df60bb
	int color;
Packit Service df60bb
	int width = im->sx;
Packit Service df60bb
	int height = im->sy;
Packit Service df60bb
	uint32 *buffer;
Packit Service df60bb
	uint32 rgba;
Packit Service df60bb
	int success;
Packit Service df60bb
Packit Service df60bb
	buffer = (uint32 *) gdCalloc(sizeof(uint32), width * height);
Packit Service df60bb
	if (!buffer) {
Packit Service df60bb
		return GD_FAILURE;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* switch off colour merging on target gd image just while we write out
Packit Service df60bb
	 * content - we want to preserve the alpha data until the user chooses
Packit Service df60bb
	 * what to do with the image */
Packit Service df60bb
	alphaBlendingFlag = im->alphaBlendingFlag;
Packit Service df60bb
	gdImageAlphaBlending(im, 0);
Packit Service df60bb
Packit Service df60bb
	success = TIFFReadRGBAImage(tif, width, height, buffer, 1);
Packit Service df60bb
Packit Service df60bb
	if (success) {
Packit Service df60bb
		for(y = 0; y < height; y++) {
Packit Service df60bb
			for(x = 0; x < width; x++) {
Packit Service df60bb
				/* if it doesn't already exist, allocate a new colour,
Packit Service df60bb
				 * else use existing one */
Packit Service df60bb
				rgba = buffer[(y * width + x)];
Packit Service df60bb
				a = (0xff - TIFFGetA(rgba)) / 2;
Packit Service df60bb
				color = gdTrueColorAlpha(TIFFGetR(rgba), TIFFGetG(rgba), TIFFGetB(rgba), a);
Packit Service df60bb
	
Packit Service df60bb
				/* set pixel colour to this colour */
Packit Service df60bb
				gdImageSetPixel(im, x, height - y - 1, color);
Packit Service df60bb
			}
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	gdFree(buffer);
Packit Service df60bb
Packit Service df60bb
	/* now reset colour merge for alpha blending routines */
Packit Service df60bb
	gdImageAlphaBlending(im, alphaBlendingFlag);
Packit Service df60bb
	return success;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
	Function: gdImageCreateFromTiffCtx
Packit Service df60bb
Packit Service df60bb
	Create a gdImage from a TIFF file input from an gdIOCtx.
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromTiffCtx(gdIOCtx *infile)
Packit Service df60bb
{
Packit Service df60bb
	TIFF *tif;
Packit Service df60bb
	tiff_handle *th;
Packit Service df60bb
Packit Service df60bb
	uint16 bps, spp, photometric;
Packit Service df60bb
	uint16 orientation;
Packit Service df60bb
	int width, height;
Packit Service df60bb
	uint16 extra, *extra_types;
Packit Service df60bb
	uint16 planar;
Packit Service df60bb
	char	has_alpha, is_bw, is_gray;
Packit Service df60bb
	char	force_rgba = FALSE;
Packit Service df60bb
	char	save_transparent;
Packit Service df60bb
	int		image_type;
Packit Service df60bb
	int   ret;
Packit Service df60bb
	float res_float;
Packit Service df60bb
Packit Service df60bb
	gdImagePtr im = NULL;
Packit Service df60bb
Packit Service df60bb
	th = new_tiff_handle(infile);
Packit Service df60bb
	if (!th) {
Packit Service df60bb
		return NULL;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	tif = TIFFClientOpen("", "rb", th, tiff_readproc,
Packit Service df60bb
	                     tiff_writeproc,
Packit Service df60bb
	                     tiff_seekproc,
Packit Service df60bb
	                     tiff_closeproc,
Packit Service df60bb
	                     tiff_sizeproc,
Packit Service df60bb
	                     tiff_mapproc,
Packit Service df60bb
	                     tiff_unmapproc);
Packit Service df60bb
Packit Service df60bb
	if (!tif) {
Packit Service df60bb
		gd_error("Cannot open TIFF image");
Packit Service df60bb
		gdFree(th);
Packit Service df60bb
		return NULL;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (!TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width)) {
Packit Service df60bb
		gd_error("TIFF error, Cannot read image width");
Packit Service df60bb
		goto error;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (!TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height)) {
Packit Service df60bb
		gd_error("TIFF error, Cannot read image width");
Packit Service df60bb
		goto error;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	TIFFGetFieldDefaulted (tif, TIFFTAG_BITSPERSAMPLE, &bps;;
Packit Service df60bb
Packit Service df60bb
	/* Unsupported bps, force to RGBA */
Packit Service df60bb
	if (bps != 1 /*bps > 8 && bps != 16*/) {
Packit Service df60bb
		force_rgba = TRUE;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	TIFFGetFieldDefaulted (tif, TIFFTAG_SAMPLESPERPIXEL, &spp;;
Packit Service df60bb
Packit Service df60bb
	if (!TIFFGetField (tif, TIFFTAG_EXTRASAMPLES, &extra, &extra_types)) {
Packit Service df60bb
		extra = 0;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (!TIFFGetField (tif, TIFFTAG_PHOTOMETRIC, &photometric)) {
Packit Service df60bb
		uint16 compression;
Packit Service df60bb
		if (TIFFGetField(tif, TIFFTAG_COMPRESSION, &compression) &&
Packit Service df60bb
		        (compression == COMPRESSION_CCITTFAX3 ||
Packit Service df60bb
		         compression == COMPRESSION_CCITTFAX4 ||
Packit Service df60bb
		         compression == COMPRESSION_CCITTRLE ||
Packit Service df60bb
		         compression == COMPRESSION_CCITTRLEW)) {
Packit Service df60bb
			gd_error("Could not get photometric. "
Packit Service df60bb
			        "Image is CCITT compressed, assuming min-is-white");
Packit Service df60bb
			photometric = PHOTOMETRIC_MINISWHITE;
Packit Service df60bb
		} else {
Packit Service df60bb
			gd_error("Could not get photometric. "
Packit Service df60bb
			        "Assuming min-is-black");
Packit Service df60bb
Packit Service df60bb
			photometric = PHOTOMETRIC_MINISBLACK;
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
	save_transparent = FALSE;
Packit Service df60bb
Packit Service df60bb
	/* test if the extrasample represents an associated alpha channel... */
Packit Service df60bb
	if (extra > 0 && (extra_types[0] == EXTRASAMPLE_ASSOCALPHA)) {
Packit Service df60bb
		has_alpha = TRUE;
Packit Service df60bb
		save_transparent = FALSE;
Packit Service df60bb
		--extra;
Packit Service df60bb
	} else if (extra > 0 && (extra_types[0] == EXTRASAMPLE_UNASSALPHA)) {
Packit Service df60bb
		has_alpha = TRUE;
Packit Service df60bb
		save_transparent = TRUE;
Packit Service df60bb
		--extra;
Packit Service df60bb
	} else if (extra > 0 && (extra_types[0] == EXTRASAMPLE_UNSPECIFIED)) {
Packit Service df60bb
		/* assuming unassociated alpha if unspecified */
Packit Service df60bb
		gd_error("alpha channel type not defined, assuming alpha is not premultiplied");
Packit Service df60bb
		has_alpha = TRUE;
Packit Service df60bb
		save_transparent = TRUE;
Packit Service df60bb
		--extra;
Packit Service df60bb
	} else {
Packit Service df60bb
		has_alpha = FALSE;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (photometric == PHOTOMETRIC_RGB && spp > 3 + extra) {
Packit Service df60bb
		has_alpha = TRUE;
Packit Service df60bb
		extra = spp - 4;
Packit Service df60bb
	} else if (photometric != PHOTOMETRIC_RGB && spp > 1 + extra) {
Packit Service df60bb
		has_alpha = TRUE;
Packit Service df60bb
		extra = spp - 2;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	is_bw = FALSE;
Packit Service df60bb
	is_gray = FALSE;
Packit Service df60bb
Packit Service df60bb
	switch (photometric) {
Packit Service df60bb
	case PHOTOMETRIC_MINISBLACK:
Packit Service df60bb
	case PHOTOMETRIC_MINISWHITE:
Packit Service df60bb
		if (!has_alpha && bps == 1 && spp == 1) {
Packit Service df60bb
			image_type = GD_INDEXED;
Packit Service df60bb
			is_bw = TRUE;
Packit Service df60bb
		} else {
Packit Service df60bb
			image_type = GD_GRAY;
Packit Service df60bb
		}
Packit Service df60bb
		break;
Packit Service df60bb
Packit Service df60bb
	case PHOTOMETRIC_RGB:
Packit Service df60bb
		image_type = GD_RGB;
Packit Service df60bb
		break;
Packit Service df60bb
Packit Service df60bb
	case PHOTOMETRIC_PALETTE:
Packit Service df60bb
		image_type = GD_INDEXED;
Packit Service df60bb
		break;
Packit Service df60bb
Packit Service df60bb
	default:
Packit Service df60bb
		force_rgba = TRUE;
Packit Service df60bb
		break;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* Force rgba if image has 1bps, but is not bw */
Packit Service df60bb
	if (bps == 1 && !is_bw) {
Packit Service df60bb
		force_rgba = TRUE;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (!TIFFGetField (tif, TIFFTAG_PLANARCONFIG, &planar)) {
Packit Service df60bb
		planar = PLANARCONFIG_CONTIG;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	/* Force rgba if image plans are not contiguous */
Packit Service df60bb
	if (force_rgba || planar != PLANARCONFIG_CONTIG) {
Packit Service df60bb
		image_type = GD_RGB;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (!force_rgba &&
Packit Service df60bb
	        (image_type == GD_PALETTE || image_type == GD_INDEXED || image_type == GD_GRAY)) {
Packit Service df60bb
		im = gdImageCreate(width, height);
Packit Service df60bb
		if (!im) goto error;
Packit Service df60bb
		readTiffColorMap(im, tif, is_bw, photometric);
Packit Service df60bb
	} else {
Packit Service df60bb
		im = gdImageCreateTrueColor(width, height);
Packit Service df60bb
		if (!im) goto error;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
#ifdef DEBUG
Packit Service df60bb
	printf("force rgba: %i\n", force_rgba);
Packit Service df60bb
	printf("has_alpha: %i\n", has_alpha);
Packit Service df60bb
	printf("save trans: %i\n", save_transparent);
Packit Service df60bb
	printf("is_bw: %i\n", is_bw);
Packit Service df60bb
	printf("is_gray: %i\n", is_gray);
Packit Service df60bb
	printf("type: %i\n", image_type);
Packit Service df60bb
#else
Packit Service df60bb
	(void)is_gray;
Packit Service df60bb
	(void)save_transparent;
Packit Service df60bb
#endif
Packit Service df60bb
Packit Service df60bb
	if (force_rgba) {
Packit Service df60bb
		ret = createFromTiffRgba(tif, im);
Packit Service df60bb
	} else if (TIFFIsTiled(tif)) {
Packit Service df60bb
		ret = createFromTiffTiles(tif, im, bps, photometric, has_alpha, is_bw, extra);
Packit Service df60bb
	} else {
Packit Service df60bb
		ret = createFromTiffLines(tif, im, bps, photometric, has_alpha, is_bw, extra);
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (!ret) {
Packit Service df60bb
		gdImageDestroy(im);
Packit Service df60bb
		im = NULL;
Packit Service df60bb
		goto error;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (TIFFGetField(tif, TIFFTAG_XRESOLUTION, &res_float)) { 
Packit Service df60bb
		im->res_x = (unsigned int)res_float;  //truncate
Packit Service df60bb
	}
Packit Service df60bb
	if (TIFFGetField(tif, TIFFTAG_YRESOLUTION, &res_float)) { 
Packit Service df60bb
		im->res_y = (unsigned int)res_float;  //truncate
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (TIFFGetField(tif, TIFFTAG_ORIENTATION, &orientation)) {
Packit Service df60bb
		switch (orientation) {
Packit Service df60bb
		case ORIENTATION_TOPLEFT:
Packit Service df60bb
		case ORIENTATION_TOPRIGHT:
Packit Service df60bb
		case ORIENTATION_BOTRIGHT:
Packit Service df60bb
		case ORIENTATION_BOTLEFT:
Packit Service df60bb
			break;
Packit Service df60bb
Packit Service df60bb
		default:
Packit Service df60bb
			gd_error("Orientation %d not handled yet!", orientation);
Packit Service df60bb
			break;
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
error:
Packit Service df60bb
	TIFFClose(tif);
Packit Service df60bb
	gdFree(th);
Packit Service df60bb
	return im;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
	Function: gdImageCreateFromTIFF
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromTiff(FILE *inFile)
Packit Service df60bb
{
Packit Service df60bb
	gdImagePtr im;
Packit Service df60bb
	gdIOCtx *in = gdNewFileCtx(inFile);
Packit Service df60bb
	if (in == NULL) return NULL;
Packit Service df60bb
	im = gdImageCreateFromTiffCtx(in);
Packit Service df60bb
	in->gd_free(in);
Packit Service df60bb
	return im;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
	Function: gdImageCreateFromTiffPtr
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromTiffPtr(int size, void *data)
Packit Service df60bb
{
Packit Service df60bb
	gdImagePtr im;
Packit Service df60bb
	gdIOCtx *in = gdNewDynamicCtxEx (size, data, 0);
Packit Service df60bb
	if (in == NULL) return NULL;
Packit Service df60bb
	im = gdImageCreateFromTiffCtx(in);
Packit Service df60bb
	in->gd_free(in);
Packit Service df60bb
	return im;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
	Function: gdImageTiff
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(void) gdImageTiff(gdImagePtr im, FILE *outFile)
Packit Service df60bb
{
Packit Service df60bb
	gdIOCtx *out = gdNewFileCtx(outFile);
Packit Service df60bb
	if (out == NULL) return;
Packit Service df60bb
	gdImageTiffCtx(im, out); /* what's an fg again? */
Packit Service df60bb
	out->gd_free(out);
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
	Function: gdImageTiffPtr
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(void *) gdImageTiffPtr(gdImagePtr im, int *size)
Packit Service df60bb
{
Packit Service df60bb
	void *rv;
Packit Service df60bb
	gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
Packit Service df60bb
	if (out == NULL) return NULL;
Packit Service df60bb
	gdImageTiffCtx(im, out); /* what's an fg again? */
Packit Service df60bb
	rv = gdDPExtractData(out, size);
Packit Service df60bb
	out->gd_free(out);
Packit Service df60bb
	return rv;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
#endif