Alien-FreeImage
view release on metacpan or search on metacpan
src/Source/FreeImage/PSDParser.cpp view on Meta::CPAN
int psdResolutionInfo_v2::Read(FreeImageIO *io, fi_handle handle) {
BYTE ShortValue[2];
int nBytes=0, n;
n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle);
nBytes += n * sizeof(ShortValue);
_Channels = (short)psdGetValue(ShortValue, sizeof(_Channels) );
n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle);
nBytes += n * sizeof(ShortValue);
_Rows = (short)psdGetValue(ShortValue, sizeof(_Rows) );
n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle);
nBytes += n * sizeof(ShortValue);
_Columns = (short)psdGetValue(ShortValue, sizeof(_Columns) );
n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle);
nBytes += n * sizeof(ShortValue);
_Depth = (short)psdGetValue(ShortValue, sizeof(_Depth) );
n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle);
nBytes += n * sizeof(ShortValue);
_Mode = (short)psdGetValue(ShortValue, sizeof(_Mode) );
return nBytes;
}
// --------------------------------------------------------------------------
psdDisplayInfo::psdDisplayInfo() {
_Opacity = _ColourSpace = -1;
for (unsigned n = 0; n < 4; ++n) {
_Colour[n] = 0;
}
_Kind = 0;
_padding = '0';
}
psdDisplayInfo::~psdDisplayInfo() {
}
int psdDisplayInfo::Read(FreeImageIO *io, fi_handle handle) {
BYTE ShortValue[2];
int nBytes=0, n;
n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle);
nBytes += n * sizeof(ShortValue);
_ColourSpace = (short)psdGetValue(ShortValue, sizeof(_ColourSpace) );
for (unsigned i = 0; i < 4; ++i) {
n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle);
nBytes += n * sizeof(ShortValue);
_Colour[i] = (short)psdGetValue(ShortValue, sizeof(_Colour[i]) );
}
n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle);
nBytes += n * sizeof(ShortValue);
_Opacity = (short)psdGetValue(ShortValue, sizeof(_Opacity) );
if((_Opacity < 0) || (_Opacity > 100)) {
throw "Invalid DisplayInfo::Opacity value";
}
BYTE c[1];
n = (int)io->read_proc(&c, sizeof(c), 1, handle);
nBytes += n * sizeof(c);
_Kind = (BYTE)psdGetValue(c, sizeof(c));
n = (int)io->read_proc(&c, sizeof(c), 1, handle);
nBytes += n * sizeof(c);
_padding = (BYTE)psdGetValue(c, sizeof(c));
if(_padding != 0) {
throw "Invalid DisplayInfo::Padding value";
}
return nBytes;
}
// --------------------------------------------------------------------------
psdThumbnail::psdThumbnail() :
_Format(-1), _Width(-1), _Height(-1), _WidthBytes(-1), _Size(-1), _CompressedSize(-1), _BitPerPixel(-1), _Planes(-1), _dib(NULL) {
}
psdThumbnail::~psdThumbnail() {
FreeImage_Unload(_dib);
}
int psdThumbnail::Read(FreeImageIO *io, fi_handle handle, int iResourceSize, bool isBGR) {
BYTE ShortValue[2], IntValue[4];
int nBytes=0, n;
// remove the header size (28 bytes) from the total data size
int iTotalData = iResourceSize - 28;
const long block_end = io->tell_proc(handle) + iTotalData;
n = (int)io->read_proc(&IntValue, sizeof(IntValue), 1, handle);
nBytes += n * sizeof(IntValue);
_Format = psdGetValue(IntValue, sizeof(_Format) );
n = (int)io->read_proc(&IntValue, sizeof(IntValue), 1, handle);
nBytes += n * sizeof(IntValue);
_Width = psdGetValue(IntValue, sizeof(_Width) );
n = (int)io->read_proc(&IntValue, sizeof(IntValue), 1, handle);
nBytes += n * sizeof(IntValue);
_Height = psdGetValue(IntValue, sizeof(_Height) );
n = (int)io->read_proc(&IntValue, sizeof(IntValue), 1, handle);
nBytes += n * sizeof(IntValue);
_WidthBytes = psdGetValue(IntValue, sizeof(_WidthBytes) );
n = (int)io->read_proc(&IntValue, sizeof(IntValue), 1, handle);
nBytes += n * sizeof(IntValue);
_Size = psdGetValue(IntValue, sizeof(_Size) );
n = (int)io->read_proc(&IntValue, sizeof(IntValue), 1, handle);
nBytes += n * sizeof(IntValue);
_CompressedSize = psdGetValue(IntValue, sizeof(_CompressedSize) );
n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle);
nBytes += n * sizeof(ShortValue);
_BitPerPixel = (short)psdGetValue(ShortValue, sizeof(_BitPerPixel) );
n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle);
nBytes += n * sizeof(ShortValue);
_Planes = (short)psdGetValue(ShortValue, sizeof(_Planes) );
const long JFIF_startpos = io->tell_proc(handle);
if(_dib) {
FreeImage_Unload(_dib);
}
if(_Format == 1) {
// kJpegRGB thumbnail image
_dib = FreeImage_LoadFromHandle(FIF_JPEG, io, handle);
if(isBGR) {
SwapRedBlue32(_dib);
}
// HACK: manually go to end of thumbnail, because (for some reason) LoadFromHandle consumes more bytes then available!
io->seek_proc(handle, block_end, SEEK_SET);
}
else {
// kRawRGB thumbnail image
// ### Unimplemented (should be trivial)
// skip the thumbnail part
io->seek_proc(handle, iTotalData, SEEK_CUR);
return iResourceSize;
}
nBytes += (block_end - JFIF_startpos);
return nBytes;
}
//---------------------------------------------------------------------------
psdICCProfile::psdICCProfile() : _ProfileSize(0), _ProfileData(NULL) {
}
psdICCProfile::~psdICCProfile() {
clear();
}
void psdICCProfile::clear() { SAFE_DELETE_ARRAY(_ProfileData); _ProfileSize = 0;}
int psdICCProfile::Read(FreeImageIO *io, fi_handle handle, int size) {
int nBytes = 0, n;
clear();
_ProfileData = new (std::nothrow) BYTE[size];
if(NULL != _ProfileData) {
n = (int)io->read_proc(_ProfileData, 1, size, handle);
_ProfileSize = size;
nBytes += n * sizeof(BYTE);
}
return nBytes;
}
//---------------------------------------------------------------------------
/**
Invert only color components, skipping Alpha/Black
(Can be useful as public/utility function)
*/
static
BOOL invertColor(FIBITMAP* dib) {
FREE_IMAGE_TYPE type = FreeImage_GetImageType(dib);
const unsigned Bpp = FreeImage_GetBPP(dib)/8;
if((type == FIT_BITMAP && Bpp == 4) || type == FIT_RGBA16) {
const unsigned width = FreeImage_GetWidth(dib);
const unsigned height = FreeImage_GetHeight(dib);
BYTE *line_start = FreeImage_GetScanLine(dib, 0);
const unsigned pitch = FreeImage_GetPitch(dib);
const unsigned triBpp = Bpp - (Bpp == 4 ? 1 : 2);
for(unsigned y = 0; y < height; y++) {
BYTE *line = line_start;
for(unsigned x = 0; x < width; x++) {
for(unsigned b=0; b < triBpp; ++b) {
line[b] = ~line[b];
}
line += Bpp;
}
line_start += pitch;
}
return TRUE;
}
else {
return FreeImage_Invert(dib);
}
}
//---------------------------------------------------------------------------
psdParser::psdParser() {
_bThumbnailFilled = false;
_bDisplayInfoFilled = false;
_bResolutionInfoFilled = false;
_bResolutionInfoFilled_v2 = false;
_bCopyright = false;
_GlobalAngle = 30;
_ColourCount = -1;
_TransparentIndex = -1;
_fi_flags = 0;
_fi_format_id = FIF_UNKNOWN;
src/Source/FreeImage/PSDParser.cpp view on Meta::CPAN
#endif
if((nCompression != PSDP_COMPRESSION_NONE && nCompression != PSDP_COMPRESSION_RLE)) {
FreeImage_OutputMessageProc(_fi_format_id, "Unsupported compression %d", nCompression);
return NULL;
}
const unsigned nWidth = _headerInfo._Width;
const unsigned nHeight = _headerInfo._Height;
const unsigned nChannels = _headerInfo._Channels;
const unsigned depth = _headerInfo._BitsPerChannel;
const unsigned bytes = (depth == 1) ? 1 : depth / 8;
// channel(plane) line (BYTE aligned)
const unsigned lineSize = (_headerInfo._BitsPerChannel == 1) ? (nWidth + 7) / 8 : nWidth * bytes;
if(nCompression == PSDP_COMPRESSION_RLE && depth > 16) {
FreeImage_OutputMessageProc(_fi_format_id, "Unsupported RLE with depth %d", depth);
return NULL;
}
// build output buffer
FIBITMAP* bitmap = NULL;
unsigned dstCh = 0;
short mode = _headerInfo._ColourMode;
if(mode == PSDP_MULTICHANNEL && nChannels < 3) {
// CM
mode = PSDP_GRAYSCALE; // C as gray, M as extra channel
}
bool needPalette = false;
switch (mode) {
case PSDP_BITMAP:
case PSDP_DUOTONE:
case PSDP_INDEXED:
case PSDP_GRAYSCALE:
dstCh = 1;
switch(depth) {
case 16:
bitmap = FreeImage_AllocateHeaderT(header_only, FIT_UINT16, nWidth, nHeight, depth*dstCh);
break;
case 32:
bitmap = FreeImage_AllocateHeaderT(header_only, FIT_FLOAT, nWidth, nHeight, depth*dstCh);
break;
default: // 1-, 8-
needPalette = true;
bitmap = FreeImage_AllocateHeader(header_only, nWidth, nHeight, depth*dstCh);
break;
}
break;
case PSDP_RGB:
case PSDP_LAB:
case PSDP_CMYK :
case PSDP_MULTICHANNEL :
// force PSDP_MULTICHANNEL CMY as CMYK
dstCh = (mode == PSDP_MULTICHANNEL && !header_only) ? 4 : MIN<unsigned>(nChannels, 4);
if(dstCh < 3) {
throw "Invalid number of channels";
}
switch(depth) {
case 16:
bitmap = FreeImage_AllocateHeaderT(header_only, dstCh < 4 ? FIT_RGB16 : FIT_RGBA16, nWidth, nHeight, depth*dstCh);
break;
case 32:
bitmap = FreeImage_AllocateHeaderT(header_only, dstCh < 4 ? FIT_RGBF : FIT_RGBAF, nWidth, nHeight, depth*dstCh);
break;
default:
bitmap = FreeImage_AllocateHeader(header_only, nWidth, nHeight, depth*dstCh);
break;
}
break;
default:
throw "Unsupported color mode";
break;
}
if(!bitmap) {
throw FI_MSG_ERROR_DIB_MEMORY;
}
// write thumbnail
FreeImage_SetThumbnail(bitmap, _thumbnail.getDib());
// @todo Add some metadata model
if(header_only) {
return bitmap;
}
// Load pixels data
const unsigned dstChannels = dstCh;
const unsigned dstBpp = (depth == 1) ? 1 : FreeImage_GetBPP(bitmap)/8;
const unsigned dstLineSize = FreeImage_GetPitch(bitmap);
BYTE* const dst_first_line = FreeImage_GetScanLine(bitmap, nHeight - 1);//<*** flipped
BYTE* line_start = new BYTE[lineSize]; //< fileline cache
switch ( nCompression ) {
case PSDP_COMPRESSION_NONE: // raw data
{
for(unsigned c = 0; c < nChannels; c++) {
if(c >= dstChannels) {
// @todo write extra channels
break;
}
const unsigned channelOffset = c * bytes;
BYTE* dst_line_start = dst_first_line;
for(unsigned h = 0; h < nHeight; ++h, dst_line_start -= dstLineSize) {//<*** flipped
io->read_proc(line_start, lineSize, 1, handle);
for (BYTE *line = line_start, *dst_line = dst_line_start; line < line_start + lineSize;
line += bytes, dst_line += dstBpp) {
#ifdef FREEIMAGE_BIGENDIAN
memcpy(dst_line + channelOffset, line, bytes);
#else
// reverse copy bytes
for (unsigned b = 0; b < bytes; ++b) {
dst_line[channelOffset + b] = line[(bytes-1) - b];
}
#endif // FREEIMAGE_BIGENDIAN
}
} //< h
}//< ch
SAFE_DELETE_ARRAY(line_start);
}
break;
case PSDP_COMPRESSION_RLE: // RLE compression
{
// The RLE-compressed data is preceeded by a 2-byte line size for each row in the data,
// store an array of these
// later use this array as WORD rleLineSizeList[nChannels][nHeight];
WORD *rleLineSizeList = new (std::nothrow) WORD[nChannels*nHeight];
if(!rleLineSizeList) {
FreeImage_Unload(bitmap);
SAFE_DELETE_ARRAY(line_start);
throw std::bad_alloc();
}
io->read_proc(rleLineSizeList, 2, nChannels * nHeight, handle);
WORD largestRLELine = 0;
for(unsigned ch = 0; ch < nChannels; ++ch) {
for(unsigned h = 0; h < nHeight; ++h) {
const unsigned index = ch * nHeight + h;
#ifndef FREEIMAGE_BIGENDIAN
SwapShort(&rleLineSizeList[index]);
#endif
if(largestRLELine < rleLineSizeList[index]) {
largestRLELine = rleLineSizeList[index];
}
}
}
BYTE* rle_line_start = new (std::nothrow) BYTE[largestRLELine];
if(!rle_line_start) {
FreeImage_Unload(bitmap);
SAFE_DELETE_ARRAY(line_start);
SAFE_DELETE_ARRAY(rleLineSizeList);
throw std::bad_alloc();
}
// Read the RLE data (assume 8-bit)
const BYTE* const line_end = line_start + lineSize;
for (unsigned ch = 0; ch < nChannels; ch++) {
const unsigned channelOffset = ch * bytes;
BYTE* dst_line_start = dst_first_line;
for(unsigned h = 0; h < nHeight; ++h, dst_line_start -= dstLineSize) {//<*** flipped
const unsigned index = ch * nHeight + h;
// - read and uncompress line -
const WORD rleLineSize = rleLineSizeList[index];
io->read_proc(rle_line_start, rleLineSize, 1, handle);
for (BYTE* rle_line = rle_line_start, *line = line_start;
rle_line < rle_line_start + rleLineSize, line < line_end;) {
int len = *rle_line++;
// NOTE len is signed byte in PackBits RLE
if ( len < 128 ) { //<- MSB is not set
// uncompressed packet
// (len + 1) bytes of data are copied
++len;
// assert we don't write beyound eol
memcpy(line, rle_line, line + len > line_end ? line_end - line : len);
line += len;
rle_line += len;
}
else if ( len > 128 ) { //< MSB is set
// RLE compressed packet
// One byte of data is repeated (âlen + 1) times
len ^= 0xFF; // same as (-len + 1) & 0xFF
len += 2; //
// assert we don't write beyound eol
memset(line, *rle_line++, line + len > line_end ? line_end - line : len);
line += len;
}
else if ( 128 == len ) {
// Do nothing
}
}//< rle_line
// - write line to destination -
if(ch >= dstChannels) {
src/Source/FreeImage/PSDParser.cpp view on Meta::CPAN
// Create empty profile and add the flag.
FreeImage_CreateICCProfile(bitmap, NULL, 0);
FreeImage_GetICCProfile(bitmap)->flags |= FIICC_COLOR_IS_CMYK;
}
}
else {
// convert to RGB
ConvertCMYKtoRGBA(bitmap);
// The ICC Profile is no longer valid
_iccProfile.clear();
// remove the pending A if not present in source
if(nChannels == 4 || nChannels == 3 ) {
FIBITMAP* t = RemoveAlphaChannel(bitmap);
if(t) {
FreeImage_Unload(bitmap);
bitmap = t;
} // else: silently fail
}
}
}
else if ( mode == PSDP_LAB && !((_fi_flags & PSD_LAB) == PSD_LAB)) {
ConvertLABtoRGB(bitmap);
}
else {
if (needPalette && FreeImage_GetPalette(bitmap)) {
if(mode == PSDP_BITMAP) {
CREATE_GREYSCALE_PALETTE_REVERSE(FreeImage_GetPalette(bitmap), 2);
}
else if(mode == PSDP_INDEXED) {
if(!_colourModeData._plColourData || _colourModeData._Length != 768 || _ColourCount < 0) {
FreeImage_OutputMessageProc(_fi_format_id, "Indexed image has no palette. Using the default grayscale one.");
} else {
_colourModeData.FillPalette(bitmap);
}
}
// GRAYSCALE, DUOTONE - use default grayscale palette
}
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
if(FreeImage_GetImageType(bitmap) == FIT_BITMAP) {
SwapRedBlue32(bitmap);
}
#endif
}
return bitmap;
}
FIBITMAP* psdParser::Load(FreeImageIO *io, fi_handle handle, int s_format_id, int flags) {
FIBITMAP *Bitmap = NULL;
_fi_flags = flags;
_fi_format_id = s_format_id;
try {
if (NULL == handle) {
throw("Cannot open file");
}
if (!_headerInfo.Read(io, handle)) {
throw("Error in header");
}
if (!_colourModeData.Read(io, handle)) {
throw("Error in ColourMode Data");
}
if (!ReadImageResources(io, handle)) {
throw("Error in Image Resource");
}
if (!ReadLayerAndMaskInfoSection(io, handle)) {
throw("Error in Mask Info");
}
Bitmap = ReadImageData(io, handle);
if (NULL == Bitmap) {
throw("Error in Image Data");
}
// set resolution info
if(NULL != Bitmap) {
unsigned res_x = 2835; // 72 dpi
unsigned res_y = 2835; // 72 dpi
if (_bResolutionInfoFilled) {
_resolutionInfo.GetResolutionInfo(res_x, res_y);
}
FreeImage_SetDotsPerMeterX(Bitmap, res_x);
FreeImage_SetDotsPerMeterY(Bitmap, res_y);
}
// set ICC profile
FreeImage_CreateICCProfile(Bitmap, _iccProfile._ProfileData, _iccProfile._ProfileSize);
if ((flags & PSD_CMYK) == PSD_CMYK) {
short mode = _headerInfo._ColourMode;
if((mode == PSDP_CMYK) || (mode == PSDP_MULTICHANNEL)) {
FreeImage_GetICCProfile(Bitmap)->flags |= FIICC_COLOR_IS_CMYK;
}
}
} catch(const char *text) {
FreeImage_OutputMessageProc(s_format_id, text);
}
catch(const std::exception& e) {
FreeImage_OutputMessageProc(s_format_id, "%s", e.what());
}
return Bitmap;
}
( run in 0.860 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )