- #121, TIFF support initial import
parent
369b24f807
commit
4ce7a01214
|
@ -49,6 +49,8 @@ else (USE_EXT_GD)
|
|||
FIND_PACKAGE(PNG REQUIRED)
|
||||
FIND_PACKAGE(ZLIB)
|
||||
FIND_PACKAGE(JPEG)
|
||||
FIND_PACKAGE(TIFF)
|
||||
|
||||
IF (NOT WIN32)
|
||||
FIND_PACKAGE(PTHREAD)
|
||||
ENDIF (NOT WIN32)
|
||||
|
@ -83,6 +85,11 @@ ENDIF (NOT WIN32)
|
|||
SET(HAVE_LIBJPEG 1)
|
||||
ENDIF(JPEG_FOUND)
|
||||
|
||||
IF(TIFF_FOUND)
|
||||
INCLUDE_DIRECTORIES(${TIFF_INCLUDE_DIR})
|
||||
SET(HAVE_LIBTIFF 1)
|
||||
ENDIF(JPEG_FOUND)
|
||||
|
||||
IF(FONTCONFIG_FOUND)
|
||||
INCLUDE_DIRECTORIES(${FONTCONFIG_INCLUDE_DIR})
|
||||
SET(HAVE_LIBFONTCONFIG 1)
|
||||
|
@ -106,7 +113,6 @@ ENDIF (NOT WIN32)
|
|||
endif(WIN32)
|
||||
|
||||
add_subdirectory(src)
|
||||
message("GD_LIB Main: ${GD_LIB}")
|
||||
endif (USE_EXT_GD)
|
||||
add_subdirectory(tests)
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ SET (LIBGD_SRC_FILES
|
|||
gd_io_ss.c
|
||||
gd_jpeg.c
|
||||
gd_png.c
|
||||
gd_tiff.c
|
||||
gd_ss.c
|
||||
gd_topal.c
|
||||
gd_wbmp.c
|
||||
|
@ -41,6 +42,6 @@ ENDIF(WIN32)
|
|||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/ ${GD_SOURCE_DIR}/src)
|
||||
|
||||
target_link_libraries(${GD_LIB} ${FREETYPE_LIBRARIES} ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${XPM_LIBRARIES} ${FONTCONFIG_LIBRARIES})
|
||||
target_link_libraries(${GD_LIB} ${FREETYPE_LIBRARIES} ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${TIFF_LIBRARIES} ${XPM_LIBRARIES} ${FONTCONFIG_LIBRARIES})
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,853 @@
|
|||
|
||||
|
||||
/*
|
||||
TIFF - Tagged Image File Format Encapsulation for GD Library
|
||||
|
||||
gd_tiff.c
|
||||
|
||||
Copyright (C) M. Retallack
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
**
|
||||
** Permission to use, copy, modify, and distribute this software and its
|
||||
** documentation for any purpose and without fee is hereby granted, provided
|
||||
** that the above copyright notice appear in all copies and that both that
|
||||
** copyright notice and this permission notice appear in supporting
|
||||
** documentation. This software is provided "as is" without express or
|
||||
** implied warranty.
|
||||
**
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Todo:
|
||||
|
||||
(suggestions only)
|
||||
Implement 2 color black/white saving using group4 fax compression
|
||||
Implement function to specify encoding to use when writing tiff data
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <gd.h>
|
||||
#include <gdfonts.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef HAVE_LIBTIFF
|
||||
|
||||
#include "tiff.h"
|
||||
#include "tiffio.h"
|
||||
|
||||
typedef struct tiff_handle
|
||||
{
|
||||
int size;
|
||||
int pos;
|
||||
gdIOCtx *ctx;
|
||||
int written;
|
||||
}
|
||||
tiff_handle;
|
||||
|
||||
/*
|
||||
Functions for reading, writing and seeking in gdIOCtx
|
||||
This allows for non-file i/o operations with no
|
||||
explicit use of libtiff fileio wrapper functions
|
||||
|
||||
Note: because libtiff requires random access, but gdIOCtx
|
||||
only supports streams, all writes are buffered
|
||||
into memory and written out on close, also all
|
||||
reads are done from a memory mapped version of the
|
||||
tiff (assuming one already exists)
|
||||
*/
|
||||
|
||||
tiff_handle * new_tiff_handle(tiff_handle *t,gdIOCtx *g)
|
||||
{
|
||||
t=malloc(sizeof(tiff_handle));
|
||||
t->size=0;
|
||||
t->pos=0;
|
||||
t->ctx=g;
|
||||
t->written=0;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/* TIFFReadWriteProc tiff_readproc - Will use gdIOCtx procs to read required
|
||||
(previously written) TIFF file content */
|
||||
tsize_t tiff_readproc(thandle_t clientdata, tdata_t data, tsize_t size)
|
||||
{
|
||||
tiff_handle *th=(tiff_handle *)clientdata;
|
||||
gdIOCtx *ctx=th->ctx;
|
||||
|
||||
size=(ctx->getBuf)(ctx, data, size);
|
||||
|
||||
return(size);
|
||||
}
|
||||
|
||||
/* TIFFReadWriteProc tiff_writeproc - Will use gdIOCtx procs to write out
|
||||
TIFF data */
|
||||
tsize_t tiff_writeproc(thandle_t clientdata, tdata_t data, tsize_t size)
|
||||
{
|
||||
tiff_handle *th=(tiff_handle *)clientdata;
|
||||
gdIOCtx *ctx=th->ctx;
|
||||
|
||||
size=(ctx->putBuf)(ctx, data, size);
|
||||
if(size+th->pos>th->size)
|
||||
{
|
||||
th->size=size+th->pos;
|
||||
th->pos+=size;
|
||||
}
|
||||
|
||||
return(size);
|
||||
}
|
||||
|
||||
/* TIFFSeekProc tiff_seekproc - used to move around the partially written TIFF */
|
||||
toff_t tiff_seekproc(thandle_t clientdata, toff_t offset, int from)
|
||||
{
|
||||
tiff_handle *th=(tiff_handle *)clientdata;
|
||||
gdIOCtx *ctx=th->ctx;
|
||||
int result;
|
||||
|
||||
switch(from)
|
||||
{
|
||||
|
||||
default:
|
||||
case SEEK_SET:
|
||||
/* just use offset */
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
/* invert offset, so that it is from start, not end as supplied */
|
||||
offset=th->size+offset;
|
||||
break;
|
||||
|
||||
case SEEK_CUR:
|
||||
/* add current position to translate it to 'from start',
|
||||
not from durrent as supplied */
|
||||
offset+=th->pos;
|
||||
break;
|
||||
}
|
||||
|
||||
/* now, move pos in both io context and buf */
|
||||
result=(ctx->seek)(ctx,offset);
|
||||
if(result)
|
||||
th->pos=offset;
|
||||
|
||||
return(result?offset:-1);
|
||||
}
|
||||
|
||||
/* TIFFCloseProc tiff_closeproc - used to finally close the TIFF file */
|
||||
int tiff_closeproc(thandle_t clientdata)
|
||||
{
|
||||
tiff_handle *th=(tiff_handle *)clientdata;
|
||||
gdIOCtx *ctx=th->ctx;
|
||||
|
||||
/*(ctx->gd_free)(ctx);*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TIFFSizeProc tiff_sizeproc */
|
||||
toff_t tiff_sizeproc(thandle_t clientdata)
|
||||
{
|
||||
tiff_handle *th=(tiff_handle *)clientdata;
|
||||
return th->size;
|
||||
}
|
||||
|
||||
/* TIFFMapFileProc tiff_mapproc() */
|
||||
int tiff_mapproc(thandle_t h, tdata_t* d, toff_t* o)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TIFFUnmapFileProc tiff_unmapproc */
|
||||
void tiff_unmapproc(thandle_t h, tdata_t d, toff_t o)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* tiffWriter
|
||||
** ----------
|
||||
** Write the gd image as a tiff file (called by gdImageTiffCtx)
|
||||
** Parameters are:
|
||||
** image: gd image structure;
|
||||
** out: the stream where to write
|
||||
** bitDepth: depth in bits of each pixel
|
||||
*/
|
||||
BGD_DECLARE(void) tiffWriter(gdImagePtr image, gdIOCtx * out,int bitDepth)
|
||||
{
|
||||
int x,y;
|
||||
int i;
|
||||
int r,g,b,a;
|
||||
TIFF *tiff;
|
||||
int width;
|
||||
int height;
|
||||
int colour;
|
||||
char *scan;
|
||||
int rowsperstrip;
|
||||
int samplesPerPixel=3;
|
||||
int bitsPerSample;
|
||||
int transparentColourR=-1;
|
||||
int transparentColourG=-1;
|
||||
int transparentColourB=-1;
|
||||
uint16 extraSamples[1];
|
||||
uint16 *colorMapRed;
|
||||
uint16 *colorMapGreen;
|
||||
uint16 *colorMapBlue;
|
||||
|
||||
tiff_handle *th;
|
||||
th=new_tiff_handle(th,out);
|
||||
extraSamples[0] = EXTRASAMPLE_ASSOCALPHA;
|
||||
|
||||
/* read in the width/height of gd image */
|
||||
width=gdImageSX(image);
|
||||
height=gdImageSY(image);
|
||||
|
||||
/* reset clip region to whole image */
|
||||
gdImageSetClip(image, 0, 0, width, height);
|
||||
|
||||
/* handle old-style single-colour mapping to 100% transparency */
|
||||
if(image->transparent!=0xffffffff)
|
||||
{
|
||||
/* set our 100% transparent colour value */
|
||||
transparentColourR=gdImageRed(image,image->transparent);
|
||||
transparentColourG=gdImageGreen(image,image->transparent);
|
||||
transparentColourB=gdImageBlue(image,image->transparent);
|
||||
}
|
||||
|
||||
/* Open tiff file writing routines, but use special read/write/seek functions
|
||||
so that tiff lib writes correct bits of tiff content to correct areas of
|
||||
file opened and modifieable by the gdIOCtx functions */
|
||||
tiff=TIFFClientOpen("", "w", th, tiff_readproc, tiff_writeproc, tiff_seekproc,
|
||||
tiff_closeproc, tiff_sizeproc, tiff_mapproc, tiff_unmapproc);
|
||||
|
||||
TIFFSetField(tiff, TIFFTAG_IMAGEWIDTH, width);
|
||||
TIFFSetField(tiff, TIFFTAG_IMAGELENGTH, height);
|
||||
TIFFSetField(tiff, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE);
|
||||
TIFFSetField(tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
|
||||
TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, bitDepth==24?PHOTOMETRIC_RGB
|
||||
:PHOTOMETRIC_PALETTE);
|
||||
bitsPerSample=bitDepth==24?8:
|
||||
bitDepth==8?8:1;
|
||||
TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, bitsPerSample);
|
||||
|
||||
/* build the color map for 8 bit images */
|
||||
if(bitDepth!=24)
|
||||
{
|
||||
colorMapRed=malloc(3 * pow(2,bitsPerSample));
|
||||
colorMapGreen=malloc(3 * pow(2,bitsPerSample));
|
||||
colorMapBlue=malloc(3 * pow(2,bitsPerSample));
|
||||
for(i=0;i<image->colorsTotal;i++)
|
||||
{
|
||||
colorMapRed[i]=gdImageRed(image,i)+(gdImageRed(image,i)*256);
|
||||
colorMapGreen[i]=gdImageGreen(image,i)+(gdImageGreen(image,i)*256);
|
||||
colorMapBlue[i]=gdImageBlue(image,i)+(gdImageBlue(image,i)*256);
|
||||
}
|
||||
TIFFSetField(tiff,TIFFTAG_COLORMAP,colorMapRed,colorMapGreen,colorMapBlue);
|
||||
samplesPerPixel=1;
|
||||
}
|
||||
|
||||
/* here, we check if the 'save alpha' flag is set on the source gd image */
|
||||
if(bitDepth==24 && (image->saveAlphaFlag || image->transparent!=0xffffffff))
|
||||
{
|
||||
/* so, we need to store the alpha values too!
|
||||
Also, tell TIFF what the extra sample means (associated alpha) */
|
||||
samplesPerPixel=4;
|
||||
TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, samplesPerPixel);
|
||||
TIFFSetField(tiff, TIFFTAG_EXTRASAMPLES, 1, extraSamples);
|
||||
}
|
||||
else
|
||||
TIFFSetField(tiff, TIFFTAG_SAMPLESPERPIXEL, samplesPerPixel);
|
||||
|
||||
TIFFSetField(tiff,TIFFTAG_ROWSPERSTRIP,1);
|
||||
|
||||
/* loop through y-coords, and x-coords */
|
||||
scan=malloc(width*samplesPerPixel);
|
||||
for(y=0;y<height;y++)
|
||||
{
|
||||
for(x=0;x<width;x++)
|
||||
{
|
||||
/* generate scan line for writing to tiff */
|
||||
colour=gdImageGetPixel(image,x,y);
|
||||
|
||||
a=(127-gdImageAlpha(image,colour))*2;
|
||||
a=(a==0xfe?0xff:a&0xff);
|
||||
b=gdImageBlue(image,colour);
|
||||
g=gdImageGreen(image,colour);
|
||||
r=gdImageRed(image,colour);
|
||||
|
||||
/* if this pixel has the same RGB as the transparent colour,
|
||||
then set alpha fully transparent */
|
||||
if(transparentColourR==r && transparentColourG==g &&
|
||||
transparentColourB==b)
|
||||
a=0x00;
|
||||
|
||||
if(bitDepth!=24)
|
||||
{
|
||||
/* write out 1 or 8 bit value in 1 byte (currently treats 1bit as 8bit) */
|
||||
scan[(x*samplesPerPixel)+0]=colour;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* write out 24 bit value in 3 (or 4 if transparent) bytes */
|
||||
if(image->saveAlphaFlag || image->transparent!=0xffffffff)
|
||||
scan[(x*samplesPerPixel)+3]=a;
|
||||
scan[(x*samplesPerPixel)+2]=b;
|
||||
scan[(x*samplesPerPixel)+1]=g;
|
||||
scan[(x*samplesPerPixel)+0]=r;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the scan line to the tiff */
|
||||
if(TIFFWriteEncodedStrip(tiff,y,scan,width*samplesPerPixel)==-1)
|
||||
{
|
||||
/* error handler here */
|
||||
fprintf(stderr, "Could not create TIFF\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* now cloase and free up resources */
|
||||
TIFFClose(tiff);
|
||||
free(scan);
|
||||
free(th);
|
||||
if(bitDepth!=24)
|
||||
{
|
||||
free(colorMapRed);
|
||||
free(colorMapGreen);
|
||||
free(colorMapBlue);
|
||||
}
|
||||
}
|
||||
|
||||
/* gdImageTiffCtx
|
||||
** --------------
|
||||
** Write the gd image as a tiff file
|
||||
** Parameters are:
|
||||
** image: gd image structure;
|
||||
** out: the stream where to write
|
||||
*/
|
||||
BGD_DECLARE(void) gdImageTiffCtx (gdImagePtr image, gdIOCtx * out)
|
||||
{
|
||||
int clipx1P,clipy1P,clipx2P,clipy2P;
|
||||
int bitDepth=24;
|
||||
|
||||
/* First, switch off clipping, or we'll not get all the image! */
|
||||
gdImageGetClip(image, &clipx1P, &clipy1P, &clipx2P, &clipy2P);
|
||||
|
||||
/* use the appropriate routine depending on the bit depth of the image */
|
||||
if(image->trueColor)
|
||||
bitDepth=24;
|
||||
else if(image->colorsTotal==2)
|
||||
bitDepth=1;
|
||||
else
|
||||
bitDepth=8;
|
||||
|
||||
tiffWriter(image,out,bitDepth);
|
||||
|
||||
/* reset clipping area to the gd image's original values */
|
||||
gdImageSetClip(image, clipx1P, clipy1P, clipx2P, clipy2P);
|
||||
}
|
||||
|
||||
|
||||
/* readColorMap
|
||||
** ------------
|
||||
** Used by tiff reading routines to generate a map between color indices
|
||||
** and their actual RGB color values.
|
||||
** return value is a chunk of memory containing
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16 *red;
|
||||
uint16 *green;
|
||||
uint16 *blue;
|
||||
}
|
||||
RgbContext;
|
||||
|
||||
void readColorMap(TIFF *tiff,RgbContext ctx)
|
||||
{
|
||||
uint32 dataSize;
|
||||
|
||||
TIFFGetField(tiff,TIFFTAG_COLORMAP,&ctx.red,&ctx.green,&ctx.blue);
|
||||
}
|
||||
|
||||
/* getRed, getGreen, getBlue
|
||||
** -------------------------
|
||||
** gets the red value for specified index from specified color map data
|
||||
** from source tiff file
|
||||
*/
|
||||
BGD_DECLARE(uint16) getColor(TIFF *tiff,RgbContext ctx,int index,char color)
|
||||
{
|
||||
uint16 bitsPerSample;
|
||||
uint16 val;
|
||||
uint32 offset;
|
||||
|
||||
TIFFGetField(tiff,TIFFTAG_BITSPERSAMPLE,&bitsPerSample);
|
||||
offset=pow(2,bitsPerSample);
|
||||
|
||||
if(color==0)
|
||||
val=ctx.red[index];
|
||||
if(color==1)
|
||||
val=ctx.green[index];
|
||||
if(color==2)
|
||||
val=ctx.blue[index];
|
||||
|
||||
val=(val>>8);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
#define getRed(t,c,i) getColor(t,c,i,0)
|
||||
#define getGreen(t,c,i) getColor(t,c,i,1)
|
||||
#define getBlue(t,c,i) getColor(t,c,i,2)
|
||||
|
||||
/* createFromTiffCtx1bit
|
||||
** ------------------------
|
||||
** Create a gdImage from a TIFF file input from an gdIOCtx
|
||||
** called by gdImageCreateFromTiffCtx() when bitsPerPixel==1
|
||||
*/
|
||||
BGD_DECLARE(gdImagePtr) createFromTiffCtx1bit (TIFF *tiff,int width,int height)
|
||||
{
|
||||
gdImagePtr im=NULL;
|
||||
int x,y,tileX,tileY,tileMaxX,tileMaxY;
|
||||
int i,j,k;
|
||||
int colour;
|
||||
char *scan;
|
||||
int compression;
|
||||
ttile_t numberOfTiles=0;
|
||||
int tileNum;
|
||||
uint32 black,white;
|
||||
unsigned long long *bitmapAsVal;
|
||||
unsigned long long bitToTest;
|
||||
unsigned long long bitTestResult;
|
||||
unsigned char byteVal;
|
||||
unsigned char byteBitToTest;
|
||||
unsigned char byteBitTestResult;
|
||||
uint32 tileSize;
|
||||
RgbContext ctx;
|
||||
|
||||
TIFFGetField(tiff,TIFFTAG_COMPRESSION,&compression);
|
||||
|
||||
if(!(im=gdImageCreate(width,height)))
|
||||
{
|
||||
TIFFClose(tiff);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* allocate both black and white for this image */
|
||||
white=gdImageColorAllocate(im, 0xff, 0xff, 0xff);
|
||||
black=gdImageColorAllocate(im, 0x00, 0x00, 0x00);
|
||||
|
||||
numberOfTiles=TIFFNumberOfTiles(tiff);
|
||||
|
||||
if(TIFFIsTiled(tiff))
|
||||
{
|
||||
TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tileMaxX);
|
||||
TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tileMaxY);
|
||||
|
||||
tileSize=TIFFTileSize(tiff);
|
||||
scan=malloc(tileSize);
|
||||
tileX=0;
|
||||
tileY=0;
|
||||
for (tileNum=0; tileNum<numberOfTiles; tileNum++)
|
||||
{
|
||||
TIFFReadEncodedTile(tiff, tileNum, scan, tileSize);
|
||||
|
||||
/* setup coords for this pixel */
|
||||
x=tileX;
|
||||
y=tileY;
|
||||
|
||||
for(i=0;i<tileSize;i+=sizeof(unsigned long long))
|
||||
{
|
||||
/* check if the next sizeof(unsigned long long) bytes are zero */
|
||||
/* if they are, move along */
|
||||
bitmapAsVal=(unsigned long long *)&scan[i];
|
||||
if(bitmapAsVal[0]!=0ull)
|
||||
{
|
||||
|
||||
/* if this chunk has some black bits, write them out, one bit at a time */
|
||||
bitToTest=1ull;
|
||||
for(j=0;j<sizeof(unsigned long long)*8;j++)
|
||||
{
|
||||
|
||||
bitTestResult=bitmapAsVal[0]&bitToTest;
|
||||
|
||||
/* if the bit at offset j is white, skip it */
|
||||
if(bitTestResult!=0ull)
|
||||
{
|
||||
gdImageSetPixel(im,x,y,black);
|
||||
}
|
||||
|
||||
/* move onto next pixel in tile's gd target area */
|
||||
x++;
|
||||
if(x>=(tileX+tileMaxX))
|
||||
{
|
||||
x=tileX;
|
||||
y++;
|
||||
}
|
||||
|
||||
bitToTest*=2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* entire section was blank - move x on by section length */
|
||||
x+=sizeof(unsigned long long)*8;
|
||||
while(x>=(tileX+tileMaxX))
|
||||
{
|
||||
x-=tileMaxX;
|
||||
y++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* move to the next tile offset */
|
||||
tileX+=tileMaxX;
|
||||
if(tileX>width)
|
||||
{
|
||||
tileX=0;
|
||||
tileY+=tileMaxY;
|
||||
}
|
||||
}
|
||||
free(scan);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* image is not tiled - assume stripped (scanline) format */
|
||||
/* printf("is a 1bit scanline tiff!\n");*/
|
||||
scan=malloc(TIFFScanlineSize(tiff));
|
||||
y=0;
|
||||
x=0;
|
||||
|
||||
for(i=0;i<height;i++)
|
||||
{
|
||||
/* looping on number of scanlines - read source scanline */
|
||||
TIFFReadScanline(tiff,scan,i,0);
|
||||
|
||||
for(j=0;j<TIFFScanlineSize(tiff);j++)
|
||||
{
|
||||
/* now, loop on content of scanline */
|
||||
byteVal=scan[j];
|
||||
byteBitToTest=0x01;
|
||||
|
||||
if(byteVal==0)
|
||||
{
|
||||
x+=8;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* now, loop through this byte, setting all bits that are not the background color */
|
||||
for(k=0;k<8;k++)
|
||||
{
|
||||
byteBitTestResult=(byteVal&byteBitToTest);
|
||||
|
||||
if(byteBitTestResult)
|
||||
{
|
||||
gdImageSetPixel(im,x,y,black);
|
||||
}
|
||||
|
||||
x++;
|
||||
byteBitToTest*=2;
|
||||
}
|
||||
}
|
||||
|
||||
y++;
|
||||
x=0;
|
||||
}
|
||||
|
||||
free(scan);
|
||||
}
|
||||
|
||||
return im;
|
||||
}
|
||||
|
||||
/* createFromTiffCtx8bit
|
||||
** ------------------------
|
||||
** Create a gdImage from a TIFF file input from an gdIOCtx
|
||||
** called by gdImageCreateFromTiffCtx() when bitsPerPixel==8
|
||||
*/
|
||||
BGD_DECLARE(gdImagePtr) createFromTiffCtx8bit (TIFF *tiff,int width,int height)
|
||||
{
|
||||
gdImagePtr im=NULL;
|
||||
int x,y;
|
||||
int i,j;
|
||||
int colorIndex;
|
||||
int colour;
|
||||
char *scan;
|
||||
uint32 numberOfTiles=0;
|
||||
uint32 tileSize;
|
||||
int tileX,tileY;
|
||||
int tileMaxX,tileMaxY;
|
||||
int tileNum;
|
||||
uint32 color;
|
||||
char *colorMap;
|
||||
RgbContext ctx;
|
||||
|
||||
if(!(im=gdImageCreate(width,height)))
|
||||
{
|
||||
TIFFClose(tiff);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
readColorMap(tiff,ctx);
|
||||
|
||||
/* set the background of the image to the first
|
||||
color in the color map */
|
||||
gdImageColorAllocate(im,getRed(tiff,ctx,0),
|
||||
getGreen(tiff,ctx,0),
|
||||
getBlue(tiff,ctx,0));
|
||||
|
||||
numberOfTiles=TIFFNumberOfTiles(tiff);
|
||||
|
||||
if(TIFFIsTiled(tiff))
|
||||
{
|
||||
/* printf("is a 8bit tiled tiff! (%d tiles)\n",numberOfTiles);*/
|
||||
TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tileMaxX);
|
||||
TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tileMaxY);
|
||||
|
||||
tileSize=TIFFTileSize(tiff);
|
||||
scan=malloc(tileSize);
|
||||
tileX=0;
|
||||
tileY=0;
|
||||
|
||||
for (tileNum=0; tileNum<numberOfTiles; tileNum++)
|
||||
{
|
||||
TIFFReadEncodedTile(tiff, tileNum, scan, tileSize);
|
||||
|
||||
/* setup coords for this pixel */
|
||||
x=tileX;
|
||||
y=tileY;
|
||||
|
||||
for(i=0;i<tileSize;i++)
|
||||
{
|
||||
/* check if the next byte is zero */
|
||||
/* if it is - background already set so move along */
|
||||
colorIndex=scan[i];
|
||||
if(colorIndex!=0x0)
|
||||
{
|
||||
color=gdImageColorResolve(im,getRed(tiff,ctx,colorIndex),
|
||||
getGreen(tiff,ctx,colorIndex),
|
||||
getBlue(tiff,ctx,colorIndex));
|
||||
|
||||
gdImageSetPixel(im,x,y,color);
|
||||
|
||||
/* move onto next pixel in tile's gd target area */
|
||||
x++;
|
||||
if(x>=(tileX+tileMaxX))
|
||||
{
|
||||
x=tileX;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* move x on to next pixel offset */
|
||||
x++;
|
||||
if(x>=(tileX+tileMaxX))
|
||||
{
|
||||
x=tileMaxX;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* move to the next tile offset */
|
||||
tileX+=tileMaxX;
|
||||
if(tileX>width)
|
||||
{
|
||||
tileX=0;
|
||||
tileY+=tileMaxY;
|
||||
}
|
||||
}
|
||||
free(scan);
|
||||
}
|
||||
else
|
||||
{
|
||||
scan=malloc(TIFFScanlineSize(tiff));
|
||||
y=0;
|
||||
x=0;
|
||||
|
||||
/* image is not tiled - assume scanline based images */
|
||||
for(i=0;i<height;i++)
|
||||
{
|
||||
/* looping on number of scanlines - read source scanline */
|
||||
TIFFReadScanline(tiff,scan,i,0);
|
||||
|
||||
for(j=0;j<TIFFScanlineSize(tiff);j++)
|
||||
{
|
||||
colorIndex=scan[j];
|
||||
color=gdImageColorResolve(im,getRed(tiff,ctx,colorIndex),
|
||||
getGreen(tiff,ctx,colorIndex),
|
||||
getBlue(tiff,ctx,colorIndex));
|
||||
|
||||
/*printf("%2x %2x %2x %2x\n",colorIndex,getRed(tiff,colorIndex),getGreen(tiff,colorIndex),getBlue(tiff,colorIndex));*/
|
||||
|
||||
gdImageSetPixel(im,x,y,color);
|
||||
x++;
|
||||
}
|
||||
|
||||
y++;
|
||||
x=0;
|
||||
}
|
||||
|
||||
free(scan);
|
||||
}
|
||||
|
||||
return im;
|
||||
}
|
||||
|
||||
/* createFromTiffCtx32bit
|
||||
** ------------------------
|
||||
** Create a 32 bit gdImage from a TIFF file input from an gdIOCtx
|
||||
** - called by gdImageCreateFromTiffCtx() when bitsPerPixel>8bit
|
||||
** This is essentially a fall-back routine; it's very slow but will
|
||||
** handle any format of tiff that libtiff supports.
|
||||
*/
|
||||
BGD_DECLARE(gdImagePtr) createFromTiffCtx32bit(TIFF *tiff,int width,int height)
|
||||
{
|
||||
gdImagePtr im=NULL;
|
||||
int r,g,b,a;
|
||||
int x,y;
|
||||
int alphaBlendingFlag=0;
|
||||
int colour;
|
||||
uint32 *scan;
|
||||
uint32 rgba;
|
||||
|
||||
if(!(im=gdImageCreateTrueColor(width,height)))
|
||||
{
|
||||
TIFFClose(tiff);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* switch off colour merging on target gd image
|
||||
just while we write out content - we want to preserve the alpha
|
||||
data until the user chooses what to do with the image */
|
||||
alphaBlendingFlag=im->alphaBlendingFlag;
|
||||
gdImageAlphaBlending(im,0);
|
||||
|
||||
/* Make sure new image begins completely black */
|
||||
gdImageColorAllocateAlpha(im, 0, 0, 0, 0x0);
|
||||
|
||||
/* loop through y-coords, and x-coords */
|
||||
scan=calloc(sizeof(uint32),width*height);
|
||||
TIFFReadRGBAImage(tiff,width,height,scan,0);
|
||||
for(y=0;y<height;y++)
|
||||
{
|
||||
for(x=0;x<width;x++)
|
||||
{
|
||||
/* if it doesn't already exist, allocate a new
|
||||
colour, else use existing one */
|
||||
rgba=scan[((y*width)+x)];
|
||||
a=(0xff - TIFFGetA(rgba))/2;
|
||||
b=TIFFGetB(rgba);
|
||||
g=TIFFGetG(rgba);
|
||||
r=TIFFGetR(rgba);
|
||||
|
||||
colour=gdImageColorResolveAlpha(im,r,g,b,a);
|
||||
|
||||
/* set pixel colour to this colour */
|
||||
gdImageSetPixel(im,x,y,colour);
|
||||
}
|
||||
}
|
||||
free(scan);
|
||||
|
||||
/* now reset colour merge for alpha blending routines */
|
||||
gdImageAlphaBlending(im,alphaBlendingFlag);
|
||||
|
||||
return (im);
|
||||
}
|
||||
|
||||
/* gdImageCreateFromTiffCtx
|
||||
** ------------------------
|
||||
** Create a gdImage from a TIFF file input from an gdIOCtx
|
||||
*/
|
||||
BGD_DECLARE(gdImagePtr) gdImageCreateFromTiffCtx (gdIOCtx * infile)
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int compression;
|
||||
uint16 samplesPerPixel;
|
||||
uint16 bitsPerSample[4];
|
||||
int bitsPerPixel;
|
||||
TIFF *tiff;
|
||||
gdImagePtr im;
|
||||
|
||||
tiff_handle *th;
|
||||
th=new_tiff_handle(th,infile);
|
||||
|
||||
tiff=TIFFClientOpen("", "rb", th, tiff_readproc, tiff_writeproc, tiff_seekproc,
|
||||
tiff_closeproc, tiff_sizeproc, tiff_mapproc, tiff_unmapproc);
|
||||
|
||||
|
||||
TIFFGetField(tiff,TIFFTAG_IMAGEWIDTH,&width);
|
||||
TIFFGetField(tiff,TIFFTAG_IMAGELENGTH,&height);
|
||||
TIFFGetField(tiff,TIFFTAG_BITSPERSAMPLE,bitsPerSample);
|
||||
TIFFGetField(tiff,TIFFTAG_SAMPLESPERPIXEL,&samplesPerPixel);
|
||||
bitsPerPixel=bitsPerSample[0]*samplesPerPixel;
|
||||
|
||||
if(bitsPerPixel==1)
|
||||
im=createFromTiffCtx1bit(tiff,width,height);
|
||||
|
||||
else if(bitsPerPixel==8)
|
||||
im=createFromTiffCtx8bit(tiff,width,height);
|
||||
|
||||
else
|
||||
im=createFromTiffCtx32bit(tiff,width,height);
|
||||
|
||||
TIFFClose(tiff);
|
||||
free(th);
|
||||
|
||||
return im;
|
||||
}
|
||||
|
||||
/* gdImageCreateFromTIFF
|
||||
** ---------------------
|
||||
*/
|
||||
BGD_DECLARE(gdImagePtr) gdImageCreateFromTiff (FILE * inFile)
|
||||
{
|
||||
gdImagePtr im;
|
||||
gdIOCtx *in = gdNewFileCtx (inFile);
|
||||
im = gdImageCreateFromTiffCtx (in);
|
||||
in->gd_free (in);
|
||||
return (im);
|
||||
}
|
||||
|
||||
BGD_DECLARE(gdImagePtr) gdImageCreateFromTiffPtr (int size, void *data)
|
||||
{
|
||||
gdImagePtr im;
|
||||
gdIOCtx *in = gdNewDynamicCtxEx (size, data, 0);
|
||||
im = gdImageCreateFromTiffCtx (in);
|
||||
in->gd_free (in);
|
||||
return im;
|
||||
}
|
||||
|
||||
/* gdImageTIFF
|
||||
** -----------
|
||||
*/
|
||||
BGD_DECLARE(void) gdImageTiff (gdImagePtr im, FILE * outFile)
|
||||
{
|
||||
gdIOCtx *out = gdNewFileCtx (outFile);
|
||||
gdImageTiffCtx (im, out); /* what's an fg again? */
|
||||
out->gd_free (out);
|
||||
}
|
||||
|
||||
/* gdImageTIFFPtr
|
||||
** --------------
|
||||
*/
|
||||
BGD_DECLARE(void *) gdImageTiffPtr (gdImagePtr im, int *size)
|
||||
{
|
||||
void *rv;
|
||||
gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
|
||||
gdImageTiffCtx (im, out); /* what's an fg again? */
|
||||
rv = gdDPExtractData (out, size);
|
||||
out->gd_free (out);
|
||||
return rv;
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue