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