Alien-FreeImage
view release on metacpan or search on metacpan
src/Source/FreeImage/PSDParser.cpp view on Meta::CPAN
_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;
}
psdParser::~psdParser() {
}
bool psdParser::ReadLayerAndMaskInfoSection(FreeImageIO *io, fi_handle handle) {
bool bSuccess = false;
BYTE DataLength[4];
int nBytes = 0;
int n = (int)io->read_proc(&DataLength, sizeof(DataLength), 1, handle);
int nTotalBytes = psdGetValue( DataLength, sizeof(DataLength) );
BYTE data[1];
while( n && ( nBytes < nTotalBytes ) ) {
data[0] = '\0';
n = (int)io->read_proc(&data, sizeof(data), 1, handle);
nBytes += n * sizeof(data);
}
if ( nBytes == nTotalBytes ) {
bSuccess = true;
}
return bSuccess;
}
bool psdParser::ReadImageResources(FreeImageIO *io, fi_handle handle, LONG length) {
psdImageResource oResource;
bool bSuccess = false;
if(length > 0) {
oResource._Length = length;
} else {
BYTE Length[4];
int n = (int)io->read_proc(&Length, sizeof(Length), 1, handle);
oResource._Length = psdGetValue( Length, sizeof(oResource._Length) );
}
int nBytes = 0;
int nTotalBytes = oResource._Length;
while(nBytes < nTotalBytes) {
int n = 0;
oResource.Reset();
n = (int)io->read_proc(&oResource._OSType, sizeof(oResource._OSType), 1, handle);
if(n != 1) {
FreeImage_OutputMessageProc(_fi_format_id, "This file contains damaged data causing an unexpected end-of-file - stop reading resources");
return false;
}
nBytes += n * sizeof(oResource._OSType);
if( (nBytes % 2) != 0 ) {
return false;
}
int nOSType = psdGetValue((BYTE*)&oResource._OSType, sizeof(oResource._OSType));
if ( PSD_RESOURCE == nOSType ) {
BYTE ID[2];
n = (int)io->read_proc(&ID, sizeof(ID), 1, handle);
nBytes += n * sizeof(ID);
oResource._ID = (short)psdGetValue( ID, sizeof(ID) );
BYTE SizeOfName;
n = (int)io->read_proc(&SizeOfName, sizeof(SizeOfName), 1, handle);
nBytes += n * sizeof(SizeOfName);
int nSizeOfName = psdGetValue( &SizeOfName, sizeof(SizeOfName) );
if ( 0 < nSizeOfName ) {
oResource._plName = new BYTE[nSizeOfName];
n = (int)io->read_proc(oResource._plName, nSizeOfName, 1, handle);
nBytes += n * nSizeOfName;
}
if ( 0 == (nSizeOfName % 2) ) {
n = (int)io->read_proc(&SizeOfName, sizeof(SizeOfName), 1, handle);
nBytes += n * sizeof(SizeOfName);
}
BYTE Size[4];
n = (int)io->read_proc(&Size, sizeof(Size), 1, handle);
nBytes += n * sizeof(Size);
oResource._Size = psdGetValue( Size, sizeof(oResource._Size) );
if ( 0 != (oResource._Size % 2) ) {
// resource data must be even
oResource._Size++;
}
if ( 0 < oResource._Size ) {
BYTE IntValue[4];
BYTE ShortValue[2];
switch( oResource._ID ) {
case 1000:
// Obsolete - Photoshop 2.0
_bResolutionInfoFilled_v2 = true;
nBytes += _resolutionInfo_v2.Read(io, handle);
break;
// ResolutionInfo structure
case 1005:
_bResolutionInfoFilled = true;
nBytes += _resolutionInfo.Read(io, handle);
break;
// DisplayInfo structure
case 1007:
_bDisplayInfoFilled = true;
nBytes += _displayInfo.Read(io, handle);
break;
// (Photoshop 4.0) Copyright flag
// Boolean indicating whether image is copyrighted. Can be set via Property suite or by user in File Info...
case 1034:
n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle);
nBytes += n * sizeof(ShortValue);
_bCopyright = (1 == psdGetValue(ShortValue, sizeof(ShortValue)));
break;
// (Photoshop 4.0) Thumbnail resource for Photoshop 4.0 only
case 1033:
// (Photoshop 5.0) Thumbnail resource (supersedes resource 1033)
case 1036:
{
_bThumbnailFilled = true;
bool bBGR = (1033==oResource._ID);
nBytes += _thumbnail.Read(io, handle, oResource._Size, bBGR);
break;
}
// (Photoshop 5.0) Global Angle
// 4 bytes that contain an integer between 0 and 359, which is the global
// lighting angle for effects layer. If not present, assumed to be 30.
case 1037:
n = (int)io->read_proc(&IntValue, sizeof(IntValue), 1, handle);
nBytes += n * sizeof(IntValue);
_GlobalAngle = psdGetValue(IntValue, sizeof(_GlobalAngle) );
break;
// ICC profile
case 1039:
nBytes += _iccProfile.Read(io, handle, oResource._Size);
break;
// (Photoshop 6.0) Indexed Color Table Count
// 2 bytes for the number of colors in table that are actually defined
case 1046:
n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle);
nBytes += n * sizeof(ShortValue);
_ColourCount = (short)psdGetValue(ShortValue, sizeof(ShortValue) );
break;
// (Photoshop 6.0) Transparency Index.
// 2 bytes for the index of transparent color, if any.
case 1047:
n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle);
nBytes += n * sizeof(ShortValue);
_TransparentIndex = (short)psdGetValue(ShortValue, sizeof(ShortValue) );
break;
default:
{
// skip resource
unsigned skip_length = MIN(oResource._Size, nTotalBytes - nBytes);
io->seek_proc(handle, skip_length, SEEK_CUR);
nBytes += skip_length;
}
break;
}
}
}
}
if (nBytes == nTotalBytes) {
bSuccess = true;
}
return bSuccess;
}
FIBITMAP* psdParser::ReadImageData(FreeImageIO *io, fi_handle handle) {
if(handle == NULL)
return NULL;
bool header_only = (_fi_flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
WORD nCompression = 0;
io->read_proc(&nCompression, sizeof(nCompression), 1, handle);
#ifndef FREEIMAGE_BIGENDIAN
SwapShort(&nCompression);
#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:
src/Source/FreeImage/PSDParser.cpp view on Meta::CPAN
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) {
// @todo write to extra channels
break;
}
// byte by byte copy a single channel to pixel
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);
SAFE_DELETE_ARRAY(rleLineSizeList);
SAFE_DELETE_ARRAY(rle_line_start);
}
break;
case 2: // ZIP without prediction, no specification
break;
case 3: // ZIP with prediction, no specification
break;
default: // Unknown format
break;
}
// --- Further process the bitmap ---
if((mode == PSDP_CMYK || mode == PSDP_MULTICHANNEL)) {
// CMYK values are "inverted", invert them back
if(mode == PSDP_MULTICHANNEL) {
invertColor(bitmap);
} else {
FreeImage_Invert(bitmap);
}
if((_fi_flags & PSD_CMYK) == PSD_CMYK) {
// keep as CMYK
if(mode == PSDP_MULTICHANNEL) {
//### we force CMY to be CMYK, but CMY has no ICC.
// 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 1.334 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )