Alien-FreeImage
view release on metacpan or search on metacpan
src/Source/FreeImage/PluginTIFF.cpp view on Meta::CPAN
}
}
}
break;
case PHOTOMETRIC_PALETTE: // color map indexed
uint16 *red;
uint16 *green;
uint16 *blue;
TIFFGetField(tiff, TIFFTAG_COLORMAP, &red, &green, &blue);
// load the palette in the DIB
if (CheckColormap(1<<bitspersample, red, green, blue) == 16) {
for (int i = (1 << bitspersample) - 1; i >= 0; i--) {
pal[i].rgbRed =(BYTE) CVT(red[i]);
pal[i].rgbGreen = (BYTE) CVT(green[i]);
pal[i].rgbBlue = (BYTE) CVT(blue[i]);
}
} else {
for (int i = (1 << bitspersample) - 1; i >= 0; i--) {
pal[i].rgbRed = (BYTE) red[i];
pal[i].rgbGreen = (BYTE) green[i];
pal[i].rgbBlue = (BYTE) blue[i];
}
}
break;
}
}
/**
Allocate a FIBITMAP
@param header_only If TRUE, allocate a 'header only' FIBITMAP, otherwise allocate a full FIBITMAP
@param fit Image type
@param width Image width in pixels
@param height Image height in pixels
@param bitspersample # bits per sample
@param samplesperpixel # samples per pixel
@return Returns the allocated image if successful, returns NULL otherwise
*/
static FIBITMAP*
CreateImageType(BOOL header_only, FREE_IMAGE_TYPE fit, int width, int height, uint16 bitspersample, uint16 samplesperpixel) {
FIBITMAP *dib = NULL;
if((width < 0) || (height < 0)) {
// check for malicious images
return NULL;
}
int bpp = bitspersample * samplesperpixel;
if(fit == FIT_BITMAP) {
// standard bitmap type
if(bpp == 16) {
if((samplesperpixel == 2) && (bitspersample == 8)) {
// 8-bit indexed + 8-bit alpha channel -> convert to 8-bit transparent
dib = FreeImage_AllocateHeader(header_only, width, height, 8);
} else {
// 16-bit RGB -> expect it to be 565
dib = FreeImage_AllocateHeader(header_only, width, height, bpp, FI16_565_RED_MASK, FI16_565_GREEN_MASK, FI16_565_BLUE_MASK);
}
}
else {
dib = FreeImage_AllocateHeader(header_only, width, height, MIN(bpp, 32), FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
}
} else {
// other bitmap types
dib = FreeImage_AllocateHeaderT(header_only, fit, width, height, bpp);
}
return dib;
}
/**
Read the TIFFTAG_SAMPLEFORMAT tag and convert to FREE_IMAGE_TYPE
@param tiff LibTIFF TIFF Handle
@param bitspersample # bit per sample
@param samplesperpixel # samples per pixel
@return Returns the image type as a FREE_IMAGE_TYPE value
*/
static FREE_IMAGE_TYPE
ReadImageType(TIFF *tiff, uint16 bitspersample, uint16 samplesperpixel) {
uint16 sampleformat = 0;
FREE_IMAGE_TYPE fit = FIT_BITMAP ;
uint16 bpp = bitspersample * samplesperpixel;
// try the sampleformat tag
if(TIFFGetField(tiff, TIFFTAG_SAMPLEFORMAT, &sampleformat)) {
switch (sampleformat) {
case SAMPLEFORMAT_UINT:
switch (bpp) {
case 1:
case 4:
case 8:
case 24:
fit = FIT_BITMAP;
break;
case 16:
// 8-bit + alpha or 16-bit greyscale
if(samplesperpixel == 2) {
fit = FIT_BITMAP;
} else {
fit = FIT_UINT16;
}
break;
case 32:
if(samplesperpixel == 4) {
fit = FIT_BITMAP;
} else {
src/Source/FreeImage/PluginTIFF.cpp view on Meta::CPAN
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) {
// ---------------------------------------------------------------------------------
// 8-bit + 8-bit alpha layer loading
// ---------------------------------------------------------------------------------
// create a new 8-bit DIB
dib = CreateImageType(header_only, image_type, width, height, bitspersample, MIN<uint16>(2, 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);
// calculate the line + pitch (separate for scr & dest)
const tmsize_t src_line = TIFFScanlineSize(tif);
// here, the pitch is 2x less than the original as we only keep the first layer
int dst_pitch = FreeImage_GetPitch(dib);
// transparency table for 8-bit + 8-bit alpha images
BYTE trns[256];
// clear the transparency table
memset(trns, 0xFF, 256 * sizeof(BYTE));
// 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);
// read the tiff lines and save them in the DIB
if(planar_config == PLANARCONFIG_CONTIG && !header_only) {
BYTE *buf = (BYTE*)malloc(TIFFStripSize(tif) * sizeof(BYTE));
if(buf == NULL) {
throw FI_MSG_ERROR_MEMORY;
}
for (uint32 y = 0; y < height; y += rowsperstrip) {
int32 nrow = (y + rowsperstrip > height ? height - y : rowsperstrip);
if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), buf, nrow * src_line) == -1) {
free(buf);
throw FI_MSG_ERROR_PARSING;
}
for (int l = 0; l < nrow; l++) {
BYTE *p = bits;
BYTE *b = buf + l * src_line;
for(uint32 x = 0; x < (uint32)(src_line / samplesperpixel); x++) {
// copy the 8-bit layer
*p = b[0];
// convert the 8-bit alpha layer to a trns table
trns[ b[0] ] = b[1];
p++;
b += samplesperpixel;
}
bits -= dst_pitch;
}
}
free(buf);
}
else if(planar_config == PLANARCONFIG_SEPARATE && !header_only) {
tmsize_t stripsize = TIFFStripSize(tif) * sizeof(BYTE);
BYTE *buf = (BYTE*)malloc(2 * stripsize);
if(buf == NULL) {
throw FI_MSG_ERROR_MEMORY;
}
BYTE *grey = buf;
BYTE *alpha = buf + stripsize;
for (uint32 y = 0; y < height; y += rowsperstrip) {
int32 nrow = (y + rowsperstrip > height ? height - y : rowsperstrip);
if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), grey, nrow * src_line) == -1) {
free(buf);
throw FI_MSG_ERROR_PARSING;
}
if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 1), alpha, nrow * src_line) == -1) {
free(buf);
throw FI_MSG_ERROR_PARSING;
}
for (int l = 0; l < nrow; l++) {
BYTE *p = bits;
BYTE *g = grey + l * src_line;
BYTE *a = alpha + l * src_line;
for(uint32 x = 0; x < (uint32)(src_line); x++) {
// copy the 8-bit layer
*p = g[0];
// convert the 8-bit alpha layer to a trns table
trns[ g[0] ] = a[0];
p++;
g++;
a++;
}
bits -= dst_pitch;
}
}
free(buf);
}
FreeImage_SetTransparencyTable(dib, &trns[0], 256);
FreeImage_SetTransparent(dib, TRUE);
} else if(loadMethod == LoadAsCMYK) {
// ---------------------------------------------------------------------------------
// CMYK loading
// ---------------------------------------------------------------------------------
// At this place, samplesperpixel could be > 4, esp. when a CMYK(A) format
// is recognized. Where all other formats are handled straight-forward, this
// format has to be handled special
BOOL isCMYKA = (photometric == PHOTOMETRIC_SEPARATED) && (samplesperpixel > 4);
// We use a temp dib to store the alpha for the CMYKA to RGBA conversion
// NOTE this is until we have Extra channels implementation.
// Also then it will be possible to merge LoadAsCMYK with LoadAsGenericStrip
FIBITMAP *alpha = NULL;
unsigned alpha_pitch = 0;
BYTE *alpha_bits = NULL;
unsigned alpha_Bpp = 0;
if(isCMYKA && !asCMYK && !header_only) {
if(bitspersample == 16) {
alpha = FreeImage_AllocateT(FIT_UINT16, width, height);
} else if (bitspersample == 8) {
alpha = FreeImage_Allocate(width, height, 8);
}
if(!alpha) {
FreeImage_OutputMessageProc(s_format_id, "Failed to allocate temporary alpha channel");
} else {
alpha_bits = FreeImage_GetScanLine(alpha, height - 1);
alpha_pitch = FreeImage_GetPitch(alpha);
alpha_Bpp = FreeImage_GetBPP(alpha) / 8;
}
}
// create a new DIB
const uint16 chCount = MIN<uint16>(samplesperpixel, 4);
dib = CreateImageType(header_only, image_type, width, height, bitspersample, chCount);
if (dib == NULL) {
FreeImage_Unload(alpha);
throw FI_MSG_ERROR_MEMORY;
}
// fill in the resolution (english or universal)
ReadResolution(tif, 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 dib_pitch = FreeImage_GetPitch(dib);
const unsigned dibBpp = FreeImage_GetBPP(dib) / 8;
const unsigned Bpc = dibBpp / chCount;
const unsigned srcBpp = bitspersample * samplesperpixel / 8;
src/Source/FreeImage/PluginTIFF.cpp view on Meta::CPAN
FreeImage_CreateICCProfile(dib, iccBuf, iccSize);
if (photometric == PHOTOMETRIC_SEPARATED && asCMYK) {
FreeImage_GetICCProfile(dib)->flags |= FIICC_COLOR_IS_CMYK;
}
// copy TIFF metadata (must be done after FreeImage_Allocate)
ReadMetadata(tif, dib);
// copy TIFF thumbnail (must be done after FreeImage_Allocate)
ReadThumbnail(io, handle, data, tif, dib);
return (FIBITMAP *)dib;
} catch (const char *message) {
if(dib) {
FreeImage_Unload(dib);
}
if(message) {
FreeImage_OutputMessageProc(s_format_id, message);
}
return NULL;
}
}
// --------------------------------------------------------------------------
static BOOL
SaveOneTIFF(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data, unsigned ifd, unsigned ifdCount) {
if (!dib || !handle || !data) {
return FALSE;
}
try {
fi_TIFFIO *fio = (fi_TIFFIO*)data;
TIFF *out = fio->tif;
const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
const uint32 width = FreeImage_GetWidth(dib);
const uint32 height = FreeImage_GetHeight(dib);
const uint16 bitsperpixel = (uint16)FreeImage_GetBPP(dib);
const FIICCPROFILE* iccProfile = FreeImage_GetICCProfile(dib);
// setup out-variables based on dib and flag options
uint16 bitspersample;
uint16 samplesperpixel;
uint16 photometric;
if(image_type == FIT_BITMAP) {
// standard image: 1-, 4-, 8-, 16-, 24-, 32-bit
samplesperpixel = ((bitsperpixel == 24) ? 3 : ((bitsperpixel == 32) ? 4 : 1));
bitspersample = bitsperpixel / samplesperpixel;
photometric = GetPhotometric(dib);
if((bitsperpixel == 8) && FreeImage_IsTransparent(dib)) {
// 8-bit transparent picture : convert later to 8-bit + 8-bit alpha
samplesperpixel = 2;
bitspersample = 8;
}
else if(bitsperpixel == 32) {
// 32-bit images : check for CMYK or alpha transparency
if((((iccProfile->flags & FIICC_COLOR_IS_CMYK) == FIICC_COLOR_IS_CMYK) || ((flags & TIFF_CMYK) == TIFF_CMYK))) {
// CMYK support
photometric = PHOTOMETRIC_SEPARATED;
TIFFSetField(out, TIFFTAG_INKSET, INKSET_CMYK);
TIFFSetField(out, TIFFTAG_NUMBEROFINKS, 4);
}
else if(photometric == PHOTOMETRIC_RGB) {
// transparency mask support
uint16 sampleinfo[1];
// unassociated alpha data is transparency information
sampleinfo[0] = EXTRASAMPLE_UNASSALPHA;
TIFFSetField(out, TIFFTAG_EXTRASAMPLES, 1, sampleinfo);
}
}
} else if(image_type == FIT_RGB16) {
// 48-bit RGB
samplesperpixel = 3;
bitspersample = bitsperpixel / samplesperpixel;
photometric = PHOTOMETRIC_RGB;
} else if(image_type == FIT_RGBA16) {
// 64-bit RGBA
samplesperpixel = 4;
bitspersample = bitsperpixel / samplesperpixel;
if((((iccProfile->flags & FIICC_COLOR_IS_CMYK) == FIICC_COLOR_IS_CMYK) || ((flags & TIFF_CMYK) == TIFF_CMYK))) {
// CMYK support
photometric = PHOTOMETRIC_SEPARATED;
TIFFSetField(out, TIFFTAG_INKSET, INKSET_CMYK);
TIFFSetField(out, TIFFTAG_NUMBEROFINKS, 4);
}
else {
photometric = PHOTOMETRIC_RGB;
// transparency mask support
uint16 sampleinfo[1];
// unassociated alpha data is transparency information
sampleinfo[0] = EXTRASAMPLE_UNASSALPHA;
TIFFSetField(out, TIFFTAG_EXTRASAMPLES, 1, sampleinfo);
}
} else if(image_type == FIT_RGBF) {
// 96-bit RGBF => store with a LogLuv encoding ?
samplesperpixel = 3;
bitspersample = bitsperpixel / samplesperpixel;
// the library converts to and from floating-point XYZ CIE values
if((flags & TIFF_LOGLUV) == TIFF_LOGLUV) {
photometric = PHOTOMETRIC_LOGLUV;
TIFFSetField(out, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT);
// TIFFSetField(out, TIFFTAG_STONITS, 1.0); // assume unknown
}
else {
// store with default compression (LZW) or with input compression flag
photometric = PHOTOMETRIC_RGB;
}
src/Source/FreeImage/PluginTIFF.cpp view on Meta::CPAN
// is it a thumbnail ?
TIFFSetField(out, TIFFTAG_SUBFILETYPE, (ifd == 0) ? (uint32)0 : (uint32)FILETYPE_REDUCEDIMAGE);
}
// palettes (image colormaps are automatically scaled to 16-bits)
if (photometric == PHOTOMETRIC_PALETTE) {
uint16 *r, *g, *b;
uint16 nColors = (uint16)FreeImage_GetColorsUsed(dib);
RGBQUAD *pal = FreeImage_GetPalette(dib);
r = (uint16 *) _TIFFmalloc(sizeof(uint16) * 3 * nColors);
if(r == NULL) {
throw FI_MSG_ERROR_MEMORY;
}
g = r + nColors;
b = g + nColors;
for (int i = nColors - 1; i >= 0; i--) {
r[i] = SCALE((uint16)pal[i].rgbRed);
g[i] = SCALE((uint16)pal[i].rgbGreen);
b[i] = SCALE((uint16)pal[i].rgbBlue);
}
TIFFSetField(out, TIFFTAG_COLORMAP, r, g, b);
_TIFFfree(r);
}
// compression tag
WriteCompression(out, bitspersample, samplesperpixel, photometric, flags);
// metadata
WriteMetadata(out, dib);
// thumbnail tag
if((ifd == 0) && (ifdCount > 1)) {
uint16 nsubifd = 1;
uint64 subifd[1];
subifd[0] = 0;
TIFFSetField(out, TIFFTAG_SUBIFD, nsubifd, subifd);
}
// read the DIB lines from bottom to top
// and save them in the TIF
// -------------------------------------
const uint32 pitch = FreeImage_GetPitch(dib);
if(image_type == FIT_BITMAP) {
// standard bitmap type
switch(bitsperpixel) {
case 1 :
case 4 :
case 8 :
{
if((bitsperpixel == 8) && FreeImage_IsTransparent(dib)) {
// 8-bit transparent picture : convert to 8-bit + 8-bit alpha
// get the transparency table
BYTE *trns = FreeImage_GetTransparencyTable(dib);
BYTE *buffer = (BYTE *)malloc(2 * width * sizeof(BYTE));
if(buffer == NULL) {
throw FI_MSG_ERROR_MEMORY;
}
for (int y = height - 1; y >= 0; y--) {
BYTE *bits = FreeImage_GetScanLine(dib, y);
BYTE *p = bits, *b = buffer;
for(uint32 x = 0; x < width; x++) {
// copy the 8-bit layer
b[0] = *p;
// convert the trns table to a 8-bit alpha layer
b[1] = trns[ b[0] ];
p++;
b += samplesperpixel;
}
// write the scanline to disc
TIFFWriteScanline(out, buffer, height - y - 1, 0);
}
free(buffer);
}
else {
// other cases
BYTE *buffer = (BYTE *)malloc(pitch * sizeof(BYTE));
if(buffer == NULL) {
throw FI_MSG_ERROR_MEMORY;
}
for (uint32 y = 0; y < height; y++) {
// get a copy of the scanline
memcpy(buffer, FreeImage_GetScanLine(dib, height - y - 1), pitch);
// write the scanline to disc
TIFFWriteScanline(out, buffer, y, 0);
}
free(buffer);
}
break;
}
case 24:
case 32:
{
BYTE *buffer = (BYTE *)malloc(pitch * sizeof(BYTE));
if(buffer == NULL) {
throw FI_MSG_ERROR_MEMORY;
}
for (uint32 y = 0; y < height; y++) {
// get a copy of the scanline
( run in 1.628 second using v1.01-cache-2.11-cpan-e1769b4cff6 )