Alien-FreeImage
view release on metacpan or search on metacpan
src/Source/FreeImage/PluginTIFF.cpp view on Meta::CPAN
@param name Name of the file handle
@param mode Specifies if the file is to be opened for reading ("r") or writing ("w")
*/
TIFF *
TIFFFdOpen(thandle_t handle, const char *name, const char *mode) {
TIFF *tif;
// Open the file; the callback will set everything up
tif = TIFFClientOpen(name, mode, handle,
_tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc,
_tiffSizeProc, _tiffMapProc, _tiffUnmapProc);
return tif;
}
/**
Open a TIFF file for reading or writing
@param name
@param mode
*/
TIFF*
TIFFOpen(const char* name, const char* mode) {
return 0;
}
// ----------------------------------------------------------
// TIFF library FreeImage-specific routines.
// ----------------------------------------------------------
void*
_TIFFmalloc(tmsize_t s) {
return malloc(s);
}
void
_TIFFfree(void *p) {
free(p);
}
void*
_TIFFrealloc(void* p, tmsize_t s) {
return realloc(p, s);
}
void
_TIFFmemset(void* p, int v, tmsize_t c) {
memset(p, v, (size_t) c);
}
void
_TIFFmemcpy(void* d, const void* s, tmsize_t c) {
memcpy(d, s, (size_t) c);
}
int
_TIFFmemcmp(const void* p1, const void* p2, tmsize_t c) {
return (memcmp(p1, p2, (size_t) c));
}
// ----------------------------------------------------------
// in FreeImage warnings and errors are disabled
// ----------------------------------------------------------
static void
msdosWarningHandler(const char* module, const char* fmt, va_list ap) {
}
TIFFErrorHandler _TIFFwarningHandler = msdosWarningHandler;
static void
msdosErrorHandler(const char* module, const char* fmt, va_list ap) {
// use this for diagnostic only (do not use otherwise, even in DEBUG mode)
/*
if (module != NULL) {
char msg[1024];
vsprintf(msg, fmt, ap);
FreeImage_OutputMessageProc(s_format_id, "%s: %s", module, msg);
}
*/
}
TIFFErrorHandler _TIFFerrorHandler = msdosErrorHandler;
// ----------------------------------------------------------
#define CVT(x) (((x) * 255L) / ((1L<<16)-1))
#define SCALE(x) (((x)*((1L<<16)-1))/255)
// ==========================================================
// Internal functions
// ==========================================================
static uint16
CheckColormap(int n, uint16* r, uint16* g, uint16* b) {
while (n-- > 0) {
if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256) {
return 16;
}
}
return 8;
}
/**
Get the TIFFTAG_PHOTOMETRIC value from the dib
*/
static uint16
GetPhotometric(FIBITMAP *dib) {
FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib);
switch(color_type) {
case FIC_MINISWHITE: // min value is white
return PHOTOMETRIC_MINISWHITE;
case FIC_MINISBLACK: // min value is black
return PHOTOMETRIC_MINISBLACK;
case FIC_PALETTE: // color map indexed
return PHOTOMETRIC_PALETTE;
case FIC_RGB: // RGB color model
case FIC_RGBALPHA: // RGB color model with alpha channel
return PHOTOMETRIC_RGB;
case FIC_CMYK: // CMYK color model
return PHOTOMETRIC_RGB; // default to RGB unless the save flag is set to TIFF_CMYK
default:
return PHOTOMETRIC_MINISBLACK;
}
}
/**
Get the resolution from the TIFF and fill the dib with universal units
*/
static void
ReadResolution(TIFF *tiff, FIBITMAP *dib) {
float fResX = 300.0;
float fResY = 300.0;
uint16 resUnit = RESUNIT_INCH;
TIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &resUnit);
TIFFGetField(tiff, TIFFTAG_XRESOLUTION, &fResX);
TIFFGetField(tiff, TIFFTAG_YRESOLUTION, &fResY);
// If we don't have a valid resolution unit and valid resolution is specified then assume inch
if (resUnit == RESUNIT_NONE && fResX > 0.0 && fResY > 0.0) {
resUnit = RESUNIT_INCH;
src/Source/FreeImage/PluginTIFF.cpp view on Meta::CPAN
}
// ---------------------------------------------------------------------------------
// get image data type
FREE_IMAGE_TYPE image_type = ReadImageType(tif, bitspersample, samplesperpixel);
// get the most appropriate loading method
TIFFLoadMethod loadMethod = FindLoadMethod(tif, image_type, flags);
// ---------------------------------------------------------------------------------
if(loadMethod == LoadAsRBGA) {
// ---------------------------------------------------------------------------------
// RGB[A] loading using the TIFFReadRGBAImage() API
// ---------------------------------------------------------------------------------
BOOL has_alpha = FALSE;
// Read the whole image into one big RGBA buffer and then
// convert it to a DIB. This is using the traditional
// TIFFReadRGBAImage() API that we trust.
uint32 *raster = NULL;
if(!header_only) {
raster = (uint32*)_TIFFmalloc(width * height * sizeof(uint32));
if (raster == NULL) {
throw FI_MSG_ERROR_MEMORY;
}
// read the image in one chunk into an RGBA array
if (!TIFFReadRGBAImage(tif, width, height, raster, 1)) {
_TIFFfree(raster);
throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
}
}
// TIFFReadRGBAImage always deliveres 3 or 4 samples per pixel images
// (RGB or RGBA, see below). Cut-off possibly present channels (additional
// alpha channels) from e.g. Photoshop. Any CMYK(A..) is now treated as RGB,
// any additional alpha channel on RGB(AA..) is lost on conversion to RGB(A)
if(samplesperpixel > 4) { // TODO Write to Extra Channels
FreeImage_OutputMessageProc(s_format_id, "Warning: %d additional alpha channel(s) ignored", samplesperpixel-4);
samplesperpixel = 4;
}
// create a new DIB (take care of different samples-per-pixel in case
// of converted CMYK image (RGB conversion is on sample per pixel less)
if (photometric == PHOTOMETRIC_SEPARATED && samplesperpixel == 4) {
samplesperpixel = 3;
}
dib = CreateImageType(header_only, image_type, width, height, bitspersample, samplesperpixel);
if (dib == NULL) {
// free the raster pointer and output an error if allocation failed
if(raster) {
_TIFFfree(raster);
}
throw FI_MSG_ERROR_DIB_MEMORY;
}
// fill in the resolution (english or universal)
ReadResolution(tif, dib);
if(!header_only) {
// read the raster lines and save them in the DIB
// with RGB mode, we have to change the order of the 3 samples RGB
// We use macros for extracting components from the packed ABGR
// form returned by TIFFReadRGBAImage.
uint32 *row = &raster[0];
if (samplesperpixel == 4) {
// 32-bit RGBA
for (uint32 y = 0; y < height; y++) {
BYTE *bits = FreeImage_GetScanLine(dib, y);
for (uint32 x = 0; x < width; x++) {
bits[FI_RGBA_BLUE] = (BYTE)TIFFGetB(row[x]);
bits[FI_RGBA_GREEN] = (BYTE)TIFFGetG(row[x]);
bits[FI_RGBA_RED] = (BYTE)TIFFGetR(row[x]);
bits[FI_RGBA_ALPHA] = (BYTE)TIFFGetA(row[x]);
if (bits[FI_RGBA_ALPHA] != 0) {
has_alpha = TRUE;
}
bits += 4;
}
row += width;
}
} else {
// 24-bit RGB
for (uint32 y = 0; y < height; y++) {
BYTE *bits = FreeImage_GetScanLine(dib, y);
for (uint32 x = 0; x < width; x++) {
bits[FI_RGBA_BLUE] = (BYTE)TIFFGetB(row[x]);
bits[FI_RGBA_GREEN] = (BYTE)TIFFGetG(row[x]);
bits[FI_RGBA_RED] = (BYTE)TIFFGetR(row[x]);
bits += 3;
}
row += width;
}
}
_TIFFfree(raster);
}
// ### Not correct when header only
FreeImage_SetTransparent(dib, has_alpha);
} else if(loadMethod == LoadAs8BitTrns) {
// ---------------------------------------------------------------------------------
src/Source/FreeImage/PluginTIFF.cpp view on Meta::CPAN
dib = t;
}
else {
FreeImage_OutputMessageProc(s_format_id, "Cannot allocate memory for buffer. CMYK image converted to RGB + pending Alpha");
}
}
}
} // !header_only
} else if(loadMethod == LoadAsGenericStrip) {
// ---------------------------------------------------------------------------------
// Generic loading
// ---------------------------------------------------------------------------------
// create a new DIB
const uint16 chCount = MIN<uint16>(samplesperpixel, 4);
dib = CreateImageType(header_only, image_type, width, height, bitspersample, chCount);
if (dib == NULL) {
throw FI_MSG_ERROR_MEMORY;
}
// fill in the resolution (english or universal)
ReadResolution(tif, dib);
// set up the colormap based on photometric
ReadPalette(tif, photometric, bitspersample, dib);
if(!header_only) {
// calculate the line + pitch (separate for scr & dest)
const tmsize_t src_line = TIFFScanlineSize(tif);
const tmsize_t dst_line = FreeImage_GetLine(dib);
const unsigned dst_pitch = FreeImage_GetPitch(dib);
const unsigned Bpp = FreeImage_GetBPP(dib) / 8;
const unsigned srcBpp = bitspersample * samplesperpixel / 8;
// In the tiff file the lines are save from up to down
// In a DIB the lines must be saved from down to up
BYTE *bits = FreeImage_GetScanLine(dib, height - 1);
// read the tiff lines and save them in the DIB
BYTE *buf = (BYTE*)malloc(TIFFStripSize(tif) * sizeof(BYTE));
if(buf == NULL) {
throw FI_MSG_ERROR_MEMORY;
}
memset(buf, 0, TIFFStripSize(tif) * sizeof(BYTE));
BOOL bThrowMessage = FALSE;
if(planar_config == PLANARCONFIG_CONTIG) {
for (uint32 y = 0; y < height; y += rowsperstrip) {
int32 strips = (y + rowsperstrip > height ? height - y : rowsperstrip);
if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), buf, strips * src_line) == -1) {
// ignore errors as they can be frequent and not really valid errors, especially with fax images
bThrowMessage = TRUE;
/*
free(buf);
throw FI_MSG_ERROR_PARSING;
*/
}
if(src_line == dst_line) {
// channel count match
for (int l = 0; l < strips; l++) {
memcpy(bits, buf + l * src_line, src_line);
bits -= dst_pitch;
}
}
else {
for (int l = 0; l < strips; l++) {
for(BYTE *pixel = bits, *src_pixel = buf + l * src_line; pixel < bits + dst_pitch; pixel += Bpp, src_pixel += srcBpp) {
AssignPixel(pixel, src_pixel, Bpp);
}
bits -= dst_pitch;
}
}
}
}
else if(planar_config == PLANARCONFIG_SEPARATE) {
const unsigned Bpc = bitspersample / 8;
BYTE* dib_strip = bits;
// - loop for strip blocks -
for (uint32 y = 0; y < height; y += rowsperstrip) {
const int32 strips = (y + rowsperstrip > height ? height - y : rowsperstrip);
// - loop for channels (planes) -
for(uint16 sample = 0; sample < samplesperpixel; sample++) {
if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, sample), buf, strips * src_line) == -1) {
// ignore errors as they can be frequent and not really valid errors, especially with fax images
bThrowMessage = TRUE;
}
if(sample >= chCount) {
// TODO Write to Extra Channel
break;
}
const unsigned channelOffset = sample * Bpc;
// - loop for strips in block -
BYTE* src_line_begin = buf;
BYTE* dst_line_begin = dib_strip;
for (int l = 0; l < strips; l++, src_line_begin += src_line, dst_line_begin -= dst_pitch ) {
// - loop for pixels in strip -
const BYTE* const src_line_end = src_line_begin + src_line;
for (BYTE* src_bits = src_line_begin, * dst_bits = dst_line_begin; src_bits < src_line_end; src_bits += Bpc, dst_bits += Bpp) {
// actually assigns channel
AssignPixel(dst_bits + channelOffset, src_bits, Bpc);
} // line
} // strips
} // channels
// done with a strip block, incr to the next
dib_strip -= strips * dst_pitch;
} // height
}
free(buf);
if(bThrowMessage) {
FreeImage_OutputMessageProc(s_format_id, "Warning: parsing error. Image may be incomplete or contain invalid data !");
}
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
SwapRedBlue32(dib);
#endif
} // !header only
} else if(loadMethod == LoadAsTiled) {
// ---------------------------------------------------------------------------------
// Tiled image loading
// ---------------------------------------------------------------------------------
uint32 tileWidth, tileHeight;
uint32 src_line = 0;
// create a new DIB
dib = CreateImageType( header_only, image_type, width, height, bitspersample, samplesperpixel);
if (dib == NULL) {
throw FI_MSG_ERROR_MEMORY;
}
// fill in the resolution (english or universal)
ReadResolution(tif, dib);
// set up the colormap based on photometric
ReadPalette(tif, photometric, bitspersample, dib);
// get the tile geometry
if(!TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tileWidth) || !TIFFGetField(tif, TIFFTAG_TILELENGTH, &tileHeight)) {
throw "Invalid tiled TIFF image";
}
// read the tiff lines and save them in the DIB
if(planar_config == PLANARCONFIG_CONTIG && !header_only) {
// get the maximum number of bytes required to contain a tile
tmsize_t tileSize = TIFFTileSize(tif);
// allocate tile buffer
BYTE *tileBuffer = (BYTE*)malloc(tileSize * sizeof(BYTE));
if(tileBuffer == NULL) {
throw FI_MSG_ERROR_MEMORY;
}
// calculate src line and dst pitch
int dst_pitch = FreeImage_GetPitch(dib);
uint32 tileRowSize = (uint32)TIFFTileRowSize(tif);
uint32 imageRowSize = (uint32)TIFFScanlineSize(tif);
// In the tiff file the lines are saved from up to down
// In a DIB the lines must be saved from down to up
BYTE *bits = FreeImage_GetScanLine(dib, height - 1);
for (uint32 y = 0; y < height; y += tileHeight) {
( run in 0.984 second using v1.01-cache-2.11-cpan-5735350b133 )