summaryrefslogtreecommitdiff
path: root/Source/FreeImage/PSDParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/FreeImage/PSDParser.cpp')
-rw-r--r--Source/FreeImage/PSDParser.cpp1526
1 files changed, 1526 insertions, 0 deletions
diff --git a/Source/FreeImage/PSDParser.cpp b/Source/FreeImage/PSDParser.cpp
new file mode 100644
index 0000000..8bcc123
--- /dev/null
+++ b/Source/FreeImage/PSDParser.cpp
@@ -0,0 +1,1526 @@
+// ==========================================================
+// Photoshop Loader
+//
+// Design and implementation by
+// - Hervé Drolon (drolon@infonie.fr)
+//
+// Based on LGPL code created and published by http://sourceforge.net/projects/elynx/
+//
+// This file is part of FreeImage 3
+//
+// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
+// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
+// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
+// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
+// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
+// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
+// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
+// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
+// THIS DISCLAIMER.
+//
+// Use at your own risk!
+// ==========================================================
+
+#include "FreeImage.h"
+#include "Utilities.h"
+#include "PSDParser.h"
+
+// PSD signature (= '8BPS')
+#define PSD_SIGNATURE 0x38425053
+// Image resource block signature (= '8BIM')
+#define PSD_RESOURCE 0x3842494D
+
+// PSD color modes
+#define PSD_BITMAP 0
+#define PSD_GRAYSCALE 1
+#define PSD_INDEXED 2
+#define PSD_RGB 3
+#define PSD_CMYK 4
+#define PSD_MULTICHANNEL 7
+#define PSD_DUOTONE 8
+#define PSD_LAB 9
+
+// PSD compression schemes
+#define PSD_COMPRESSION_NONE 0 // Raw data
+#define PSD_COMPRESSION_RLE 1 // RLE compression (same as TIFF packed bits)
+
+#define SAFE_DELETE_ARRAY(_p_) { if (NULL != (_p_)) { delete [] (_p_); (_p_) = NULL; } }
+
+// --------------------------------------------------------------------------
+
+static inline int
+psdGetValue(const BYTE * iprBuffer, const int iBytes) {
+ int v = iprBuffer[0];
+ for (int i=1; i<iBytes; ++i) {
+ v = (v << 8) | iprBuffer[i];
+ }
+ return v;
+}
+
+// --------------------------------------------------------------------------
+
+psdHeaderInfo::psdHeaderInfo() : _Channels(-1), _Height(-1), _Width(-1), _BitsPerPixel(-1), _ColourMode(-1) {
+}
+
+psdHeaderInfo::~psdHeaderInfo() {
+}
+
+bool psdHeaderInfo::Read(FreeImageIO *io, fi_handle handle) {
+ bool bSuccess = false;
+ psdHeader header;
+
+ const int n = (int)io->read_proc(&header, sizeof(header), 1, handle);
+ if(!n) {
+ return false;
+ }
+
+ // check the signature
+ int nSignature = psdGetValue(header.Signature, sizeof(header.Signature));
+ if (PSD_SIGNATURE == nSignature) {
+ // check the version
+ int nVersion = psdGetValue( header.Version, sizeof(header.Version) );
+ if (1 == nVersion) {
+ // header.Reserved must be zero
+ unsigned i = 0;
+ bool bOK = true;
+ while ( (i < 6) && bOK ) {
+ if ( '\0' != header.Reserved[i] ) {
+ bOK = false;
+ break;
+ }
+ i++;
+ }
+ bSuccess = bOK;
+ if (bSuccess) {
+ // read the header
+ _Channels = (short)psdGetValue( header.Channels, sizeof(header.Channels) );
+ _Height = psdGetValue( header.Rows, sizeof(header.Rows) );
+ _Width = psdGetValue( header.Columns, sizeof(header.Columns) );
+ _BitsPerPixel = (short)psdGetValue( header.Depth, sizeof(header.Depth) );
+ _ColourMode = (short)psdGetValue( header.Mode, sizeof(header.Mode) );
+ }
+ }
+ }
+
+ return bSuccess;
+}
+
+// --------------------------------------------------------------------------
+
+psdColourModeData::psdColourModeData() : _Length(-1), _plColourData(NULL) {
+}
+
+psdColourModeData::~psdColourModeData() {
+ SAFE_DELETE_ARRAY(_plColourData);
+}
+
+bool psdColourModeData::Read(FreeImageIO *io, fi_handle handle) {
+ if (0 < _Length) {
+ SAFE_DELETE_ARRAY(_plColourData);
+ }
+
+ BYTE Length[4];
+ io->read_proc(&Length, sizeof(Length), 1, handle);
+
+ _Length = psdGetValue( Length, sizeof(_Length) );
+ if (0 < _Length) {
+ _plColourData = new BYTE[_Length];
+ io->read_proc(_plColourData, _Length, 1, handle);
+ }
+
+ return true;
+}
+
+bool psdColourModeData::FillPalette(FIBITMAP *dib) {
+ RGBQUAD *pal = FreeImage_GetPalette(dib);
+ if(pal) {
+ for (int i = 0; i < 256; i++) {
+ pal[i].rgbRed = _plColourData[i + 0*256];
+ pal[i].rgbGreen = _plColourData[i + 1*256];
+ pal[i].rgbBlue = _plColourData[i + 2*256];
+ }
+ return true;
+ }
+ return false;
+}
+
+// --------------------------------------------------------------------------
+
+psdImageResource::psdImageResource() : _plName (0) {
+ Reset();
+}
+
+psdImageResource::~psdImageResource() {
+ SAFE_DELETE_ARRAY(_plName);
+}
+
+void psdImageResource::Reset() {
+ _Length = -1;
+ memset( _OSType, '\0', sizeof(_OSType) );
+ _ID = -1;
+ SAFE_DELETE_ARRAY(_plName);
+ _Size = -1;
+}
+
+// --------------------------------------------------------------------------
+
+psdResolutionInfo::psdResolutionInfo() : _widthUnit(-1), _heightUnit(-1), _hRes(-1), _vRes(-1), _hResUnit(-1), _vResUnit(-1) {
+}
+
+psdResolutionInfo::~psdResolutionInfo() {
+}
+
+int psdResolutionInfo::Read(FreeImageIO *io, fi_handle handle) {
+ BYTE IntValue[4], ShortValue[2];
+ int nBytes=0, n;
+
+ // Horizontal resolution in pixels per inch.
+ n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle);
+ nBytes += n * sizeof(ShortValue);
+ _hRes = (short)psdGetValue(ShortValue, sizeof(_hRes) );
+ // 1=display horizontal resolution in pixels per inch; 2=display horizontal resolution in pixels per cm.
+ n = (int)io->read_proc(&IntValue, sizeof(IntValue), 1, handle);
+ nBytes += n * sizeof(IntValue);
+ _hResUnit = psdGetValue(IntValue, sizeof(_hResUnit) );
+ // Display width as 1=inches; 2=cm; 3=points; 4=picas; 5=columns.
+ n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle);
+ nBytes += n * sizeof(ShortValue);
+ _widthUnit = (short)psdGetValue(ShortValue, sizeof(_widthUnit) );
+ // Vertical resolution in pixels per inch.
+ n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle);
+ nBytes += n * sizeof(ShortValue);
+ _vRes = (short)psdGetValue(ShortValue, sizeof(_vRes) );
+ // 1=display vertical resolution in pixels per inch; 2=display vertical resolution in pixels per cm.
+ n = (int)io->read_proc(&IntValue, sizeof(IntValue), 1, handle);
+ nBytes += n * sizeof(IntValue);
+ _vResUnit = psdGetValue(IntValue, sizeof(_vResUnit) );
+ // Display height as 1=inches; 2=cm; 3=points; 4=picas; 5=columns.
+ n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle);
+ nBytes += n * sizeof(ShortValue);
+ _heightUnit = (short)psdGetValue(ShortValue, sizeof(_heightUnit) );
+
+ return nBytes;
+}
+
+void psdResolutionInfo::GetResolutionInfo(unsigned &res_x, unsigned &res_y) {
+ if(_hResUnit == 1) {
+ // convert pixels / inch to pixel / m
+ res_x = (unsigned) (_hRes / 0.0254000 + 0.5);
+ } else if(_hResUnit == 2) {
+ // convert pixels / cm to pixel / m
+ res_x = (unsigned) (_hRes * 100.0 + 0.5);
+ }
+ if(_vResUnit == 1) {
+ // convert pixels / inch to pixel / m
+ res_y = (unsigned) (_vRes / 0.0254000 + 0.5);
+ } else if(_vResUnit == 2) {
+ // convert pixels / cm to pixel / m
+ res_y = (unsigned) (_vRes * 100.0 + 0.5);
+ }
+}
+
+// --------------------------------------------------------------------------
+
+psdResolutionInfo_v2::psdResolutionInfo_v2() {
+ _Channels = _Rows = _Columns = _Depth = _Mode = -1;
+}
+
+psdResolutionInfo_v2::~psdResolutionInfo_v2() {
+}
+
+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) );
+ assert( 0 <= _Opacity );
+ assert( 100 >= _Opacity );
+
+ 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));
+ assert( 0 == _padding );
+
+ return nBytes;
+}
+
+// --------------------------------------------------------------------------
+
+psdThumbnail::psdThumbnail() :
+_Format(-1), _Width(-1), _Height(-1), _WidthBytes(-1), _Size(-1), _CompressedSize(-1), _BitPerPixel(-1), _Planes(-1), _plData(NULL) {
+}
+
+psdThumbnail::~psdThumbnail() {
+ SAFE_DELETE_ARRAY(_plData);
+}
+
+int psdThumbnail::Read(FreeImageIO *io, fi_handle handle, int iTotalData, bool isBGR) {
+ BYTE c[1], ShortValue[2], IntValue[4];
+ int nBytes=0, n;
+
+ 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) );
+
+ _plData = new BYTE[iTotalData];
+
+ if (isBGR) {
+ // In BGR format
+ for (int i=0; i<iTotalData; i+=3 ) {
+ n = (int)io->read_proc(&c, sizeof(BYTE), 1, handle);
+ nBytes += n * sizeof(BYTE);
+ _plData[i+2] = (BYTE)psdGetValue(c, sizeof(BYTE) );
+
+ n = (int)io->read_proc(&c, sizeof(BYTE), 1, handle);
+ nBytes += n * sizeof(BYTE);
+ _plData[i+1] = (BYTE)psdGetValue(c, sizeof(BYTE) );
+
+ n = (int)io->read_proc(&c, sizeof(BYTE), 1, handle);
+ nBytes += n * sizeof(BYTE);
+ _plData[i+0] = (BYTE)psdGetValue(c, sizeof(BYTE) );
+ }
+ } else {
+ // In RGB format
+ for (int i=0; i<iTotalData; ++i) {
+ n = (int)io->read_proc(&c, sizeof(BYTE), 1, handle);
+ nBytes += n * sizeof(BYTE);
+ _plData[i] = (BYTE)psdGetValue(c, sizeof(BYTE) );
+ }
+ }
+
+ return nBytes;
+}
+
+//---------------------------------------------------------------------------
+
+psdICCProfile::psdICCProfile() : _ProfileSize(0), _ProfileData(NULL) {
+}
+
+psdICCProfile::~psdICCProfile() {
+ SAFE_DELETE_ARRAY(_ProfileData);
+}
+
+int psdICCProfile::Read(FreeImageIO *io, fi_handle handle, int size) {
+ int nBytes = 0, n;
+
+ SAFE_DELETE_ARRAY(_ProfileData);
+ _ProfileData = new BYTE[size];
+ if(NULL != _ProfileData) {
+ n = (int)io->read_proc(_ProfileData, 1, size, handle);
+ _ProfileSize = size;
+ nBytes += n * sizeof(BYTE);
+ }
+
+ return nBytes;
+}
+
+//---------------------------------------------------------------------------
+
+static inline int d2i(double value) {
+ return (int)floor(value + 0.5);
+}
+
+/**
+CMYK to RGB 8-bit conversion
+*/
+static void CMYKToRGB8(float iC, float iM, float iY, float iK, RGBTRIPLE *rgb) {
+ int r = d2i( ( 1.f - (iC *(1.f - iK) + iK ) ) * 255.f );
+ int g = d2i( ( 1.f - (iM *(1.f - iK) + iK ) ) * 255.f );
+ int b = d2i( ( 1.f - (iY *(1.f - iK) + iK ) ) * 255.f );
+
+ if (r < 0) r = 0; else if (r > 255) r = 255;
+ if (g < 0) g = 0; else if (g > 255) g = 255;
+ if (b < 0) b = 0; else if (b > 255) b = 255;
+
+ rgb->rgbtRed = (BYTE)r;
+ rgb->rgbtGreen = (BYTE)g;
+ rgb->rgbtBlue = (BYTE)b;
+}
+
+/**
+CMYK to RGB 16-bit conversion
+*/
+static void CMYKToRGB16(float iC, float iM, float iY, float iK, FIRGB16 *rgb) {
+ int r = d2i( ( 1.f - (iC *(1.f - iK) + iK ) ) * 65535.f );
+ int g = d2i( ( 1.f - (iM *(1.f - iK) + iK ) ) * 65535.f );
+ int b = d2i( ( 1.f - (iY *(1.f - iK) + iK ) ) * 65535.f );
+
+ if (r < 0) r = 0; else if (r > 65535) r = 65535;
+ if (g < 0) g = 0; else if (g > 65535) g = 65535;
+ if (b < 0) b = 0; else if (b > 65535) b = 65535;
+
+ rgb->red = (WORD)r;
+ rgb->green = (WORD)g;
+ rgb->blue = (WORD)b;
+}
+
+#define PSD_CLAMP(v, min, max) ((v < min) ? min : (v > max) ? max : v)
+
+/**
+CIELab -> XYZ conversion from http://www.easyrgb.com/
+*/
+static void CIELabToXYZ(float L, float a, float b, float *X, float *Y, float *Z) {
+ float pow_3;
+
+ // CIELab -> XYZ conversion
+ // ------------------------
+ float var_Y = (L + 16.F ) / 116.F;
+ float var_X = a / 500.F + var_Y;
+ float var_Z = var_Y - b / 200.F;
+
+ pow_3 = powf(var_Y, 3);
+ if(pow_3 > 0.008856F) {
+ var_Y = pow_3;
+ } else {
+ var_Y = ( var_Y - 16.F / 116.F ) / 7.787F;
+ }
+ pow_3 = powf(var_X, 3);
+ if(pow_3 > 0.008856F) {
+ var_X = pow_3;
+ } else {
+ var_X = ( var_X - 16.F / 116.F ) / 7.787F;
+ }
+ pow_3 = powf(var_Z, 3);
+ if(pow_3 > 0.008856F) {
+ var_Z = pow_3;
+ } else {
+ var_Z = ( var_Z - 16.F / 116.F ) / 7.787F;
+ }
+
+ static const float ref_X = 95.047F;
+ static const float ref_Y = 100.000F;
+ static const float ref_Z = 108.883F;
+
+ *X = ref_X * var_X; // ref_X = 95.047 (Observer= 2°, Illuminant= D65)
+ *Y = ref_Y * var_Y; // ref_Y = 100.000
+ *Z = ref_Z * var_Z; // ref_Z = 108.883
+}
+
+/**
+XYZ -> RGB conversion from http://www.easyrgb.com/
+*/
+static void XYZToRGB(float X, float Y, float Z, float *R, float *G, float *B) {
+ float var_X = X / 100; //X from 0 to 95.047 (Observer = 2°, Illuminant = D65)
+ float var_Y = Y / 100; //Y from 0 to 100.000
+ float var_Z = Z / 100; //Z from 0 to 108.883
+
+ float var_R = var_X * 3.2406F + var_Y * -1.5372F + var_Z * -0.4986F;
+ float var_G = var_X * -0.9689F + var_Y * 1.8758F + var_Z * 0.0415F;
+ float var_B = var_X * 0.0557F + var_Y * -0.2040F + var_Z * 1.0570F;
+
+ float exponent = 1.F / 2.4F;
+
+ if(var_R > 0.0031308F) {
+ var_R = 1.055F * powf(var_R, exponent) - 0.055F;
+ } else {
+ var_R = 12.92F * var_R;
+ }
+ if(var_G > 0.0031308F) {
+ var_G = 1.055F * powf(var_G, exponent) - 0.055F;
+ } else {
+ var_G = 12.92F * var_G;
+ }
+ if(var_B > 0.0031308F) {
+ var_B = 1.055F * powf(var_B, exponent) - 0.055F;
+ } else {
+ var_B = 12.92F * var_B;
+ }
+
+ *R = var_R;
+ *G = var_G;
+ *B = var_B;
+}
+
+static void CIELabToRGB16(float L, float a, float b, FIRGB16 *rgb) {
+ float X, Y, Z;
+ float R, G, B;
+ const float max_value = 65535.0F;
+
+ CIELabToXYZ(L, a, b, &X, &Y, &Z);
+ XYZToRGB(X, Y, Z, &R, &G, &B);
+ rgb->red = (WORD)PSD_CLAMP(R * max_value, 0, max_value);
+ rgb->green = (WORD)PSD_CLAMP(G * max_value, 0, max_value);
+ rgb->blue = (WORD)PSD_CLAMP(B * max_value, 0, max_value);
+}
+
+static void CIELabToRGB8(float L, float a, float b, RGBTRIPLE *rgb) {
+ float X, Y, Z;
+ float R, G, B;
+ const float max_value = 255.0F;
+
+ CIELabToXYZ(L, a, b, &X, &Y, &Z);
+ XYZToRGB(X, Y, Z, &R, &G, &B);
+ rgb->rgbtRed = (BYTE)PSD_CLAMP(R * max_value, 0, max_value);
+ rgb->rgbtGreen = (BYTE)PSD_CLAMP(G * max_value, 0, max_value);
+ rgb->rgbtBlue = (BYTE)PSD_CLAMP(B * max_value, 0, max_value);
+}
+
+//---------------------------------------------------------------------------
+
+psdParser::psdParser() {
+ _bThumbnailFilled = false;
+ _bDisplayInfoFilled = false;
+ _bResolutionInfoFilled = false;
+ _bResolutionInfoFilled_v2 = false;
+ _bCopyright = false;
+ _GlobalAngle = 30;
+ _ColourCount = -1;
+ _TransparentIndex = -1;
+}
+
+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);
+ }
+
+ assert( nBytes == nTotalBytes );
+ if ( nBytes == nTotalBytes ) {
+ bSuccess = true;
+ }
+
+ return bSuccess;
+}
+
+bool psdParser::ReadImageResource(FreeImageIO *io, fi_handle handle) {
+ psdImageResource oResource;
+ bool bSuccess = false;
+
+ 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) {
+ n = 0;
+ oResource.Reset();
+
+ n = (int)io->read_proc(&oResource._OSType, sizeof(oResource._OSType), 1, handle);
+ nBytes += n * sizeof(oResource._OSType);
+ assert( 0 == (nBytes % 2) );
+
+ 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);
+ int nTotalData = oResource._Size - 28; // header
+ nBytes += _thumbnail.Read(io, handle, nTotalData, 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
+ BYTE c[1];
+ for(int i=0; i<oResource._Size; ++i) {
+ n = (int)io->read_proc(&c, sizeof(c), 1, handle);
+ nBytes += n * sizeof(c);
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ assert(nBytes == nTotalBytes);
+ if (nBytes == nTotalBytes) {
+ bSuccess = true;
+ }
+
+ return bSuccess;
+
+}
+
+FIBITMAP* psdParser::ProcessBuffer(BYTE * iprData) {
+ assert(NULL != iprData);
+
+ FIBITMAP *Bitmap = NULL;
+ int nHeight = _headerInfo._Height;
+ int nWidth = _headerInfo._Width;
+ unsigned bytes = _headerInfo._BitsPerPixel / 8;
+ int nChannels = _headerInfo._Channels;
+
+ switch (_headerInfo._ColourMode) {
+ case PSD_BITMAP: // Bitmap
+ {
+ // monochrome 1-bit
+ FIBITMAP *dib = FreeImage_Allocate(nWidth, nHeight, 1);
+ if (NULL != dib) {
+ // fill the palette
+ RGBQUAD *pal = FreeImage_GetPalette(dib);
+ if(pal) {
+ for (int i = 0; i < 2; i++) {
+ BYTE val = i ? 0x0 : 0xFF;
+ pal[i].rgbRed = val;
+ pal[i].rgbGreen = val;
+ pal[i].rgbBlue = val;
+ }
+ }
+ // copy buffer
+ BYTE *src_bits = (BYTE*)iprData;
+ BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1);
+ unsigned src_pitch = (nWidth + 7) / 8;
+ unsigned dst_pitch = FreeImage_GetPitch(dib);
+ for(int y = 0; y < nHeight; y++) {
+ memcpy(dst_bits, src_bits, src_pitch);
+ src_bits += src_pitch;
+ dst_bits -= dst_pitch;
+ }
+ }
+ Bitmap = dib;
+ }
+ break;
+
+ case PSD_GRAYSCALE: // Grayscale
+ case PSD_DUOTONE: // Duotone
+ case PSD_RGB: // RGB
+ {
+ // 16-bit / channel
+ // --------------------------------------------------------------
+ if (16 == _headerInfo._BitsPerPixel) {
+ if (1 == nChannels) {
+ // L 16-bit
+ FIBITMAP *dib = FreeImage_AllocateT(FIT_UINT16, nWidth, nHeight);
+ if (NULL != dib) {
+ // just copy buffer
+ BYTE *src_bits = (BYTE*)iprData;
+ BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1);
+ unsigned src_pitch = nChannels * nWidth * bytes;
+ unsigned dst_pitch = FreeImage_GetPitch(dib);
+ for(int y = 0; y < nHeight; y++) {
+ memcpy(dst_bits, src_bits, src_pitch);
+ src_bits += src_pitch;
+ dst_bits -= dst_pitch;
+ }
+ Bitmap = dib;
+ }
+ }
+ else if (2 == nChannels) {
+ // LA 16-bit : convert to RGBA 16-bit
+ FIBITMAP *dib = FreeImage_AllocateT(FIT_RGBA16, nWidth, nHeight);
+ if (NULL != dib) {
+ unsigned short *src_bits = (unsigned short*)iprData;
+ FIRGBA16 *dst_bits = (FIRGBA16*)FreeImage_GetScanLine(dib, nHeight-1);
+ unsigned pitch = FreeImage_GetPitch(dib) / sizeof(FIRGBA16);
+ for(int y = 0; y < nHeight; y++) {
+ for(int x = 0; x < nWidth; x++) {
+ dst_bits[x].red = src_bits[0];
+ dst_bits[x].green = src_bits[0];
+ dst_bits[x].blue = src_bits[0];
+ dst_bits[x].alpha = src_bits[1];
+ src_bits += nChannels;
+ }
+ dst_bits -= pitch;
+ }
+ Bitmap = dib;
+ }
+ }
+ else if (3 == nChannels) {
+ // RGB 16-bit
+ FIBITMAP *dib = FreeImage_AllocateT(FIT_RGB16, nWidth, nHeight);
+ if (NULL != dib) {
+ // just copy buffer
+ BYTE *src_bits = (BYTE*)iprData;
+ BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1);
+ unsigned src_pitch = nChannels * nWidth * bytes;
+ unsigned dst_pitch = FreeImage_GetPitch(dib);
+ for(int y = 0; y < nHeight; y++) {
+ memcpy(dst_bits, src_bits, src_pitch);
+ src_bits += src_pitch;
+ dst_bits -= dst_pitch;
+ }
+ Bitmap = dib;
+ }
+ }
+ else if (4 == nChannels) {
+ // RGBA 16-bit
+ FIBITMAP *dib = FreeImage_AllocateT(FIT_RGBA16, nWidth, nHeight);
+ if (NULL != dib) {
+ // just copy buffer
+ BYTE *src_bits = (BYTE*)iprData;
+ BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1);
+ unsigned src_pitch = nChannels * nWidth * bytes;
+ unsigned dst_pitch = FreeImage_GetPitch(dib);
+ for(int y = 0; y < nHeight; y++) {
+ memcpy(dst_bits, src_bits, src_pitch);
+ src_bits += src_pitch;
+ dst_bits -= dst_pitch;
+ }
+ Bitmap = dib;
+ }
+ }
+ }
+ // 8-bit / channel
+ // --------------------------------------------------------------
+ else if (8 == _headerInfo._BitsPerPixel) {
+ if (1 == nChannels) {
+ // L 8-bit
+ FIBITMAP *dib = FreeImage_Allocate(nWidth, nHeight, 8);
+ if (NULL != dib) {
+ // build a greyscale palette
+ RGBQUAD *pal = FreeImage_GetPalette(dib);
+ for (int i = 0; i < 256; i++) {
+ pal[i].rgbRed = (BYTE)i;
+ pal[i].rgbGreen = (BYTE)i;
+ pal[i].rgbBlue = (BYTE)i;
+ }
+ // just copy buffer
+ BYTE *src_bits = (BYTE*)iprData;
+ BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1);
+ unsigned src_pitch = nChannels * nWidth * bytes;
+ unsigned dst_pitch = FreeImage_GetPitch(dib);
+ for(int y = 0; y < nHeight; y++) {
+ memcpy(dst_bits, src_bits, src_pitch);
+ src_bits += src_pitch;
+ dst_bits -= dst_pitch;
+ }
+ Bitmap = dib;
+ }
+ }
+ else if (2 == nChannels) {
+ // LA 8-bit : convert to RGBA 32-bit
+ FIBITMAP *dib = FreeImage_Allocate(nWidth, nHeight, 32);
+ if (NULL != dib) {
+ BYTE *src_bits = (BYTE*)iprData;
+ BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1);
+ unsigned src_pitch = nChannels * nWidth * bytes;
+ unsigned dst_pitch = FreeImage_GetPitch(dib);
+ for(int y = 0; y < nHeight; y++) {
+ BYTE *p_src = src_bits;
+ BYTE *p_dst = dst_bits;
+ for(int x = 0; x < nWidth; x++) {
+ p_dst[FI_RGBA_RED] = p_src[0];
+ p_dst[FI_RGBA_GREEN] = p_src[0];
+ p_dst[FI_RGBA_BLUE] = p_src[0];
+ p_dst[FI_RGBA_ALPHA] = p_src[1];
+ p_src += nChannels;
+ p_dst += 4;
+ }
+ src_bits += src_pitch;
+ dst_bits -= dst_pitch;
+ }
+ Bitmap = dib;
+ }
+ }
+ else if (3 == nChannels) {
+ // RGB 8-bit
+ FIBITMAP *dib = FreeImage_Allocate(nWidth, nHeight, 24);
+ if (NULL != dib) {
+ // just copy buffer
+ BYTE *src_bits = (BYTE*)iprData;
+ BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1);
+ unsigned src_pitch = nChannels * nWidth * bytes;
+ unsigned dst_pitch = FreeImage_GetPitch(dib);
+ for(int y = 0; y < nHeight; y++) {
+ BYTE *p_src = src_bits;
+ BYTE *p_dst = dst_bits;
+ for(int x = 0; x < nWidth; x++) {
+ p_dst[FI_RGBA_RED] = p_src[0];
+ p_dst[FI_RGBA_GREEN] = p_src[1];
+ p_dst[FI_RGBA_BLUE] = p_src[2];
+ p_src += nChannels;
+ p_dst += nChannels;
+ }
+ src_bits += src_pitch;
+ dst_bits -= dst_pitch;
+ }
+ Bitmap = dib;
+ }
+ }
+ else if (4 == nChannels) {
+ // RGBA 8-bit
+ FIBITMAP *dib = FreeImage_Allocate(nWidth, nHeight, 32);
+ if (NULL != dib) {
+ // just copy buffer
+ BYTE *src_bits = (BYTE*)iprData;
+ BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1);
+ unsigned src_pitch = nChannels * nWidth * bytes;
+ unsigned dst_pitch = FreeImage_GetPitch(dib);
+ for(int y = 0; y < nHeight; y++) {
+ BYTE *p_src = src_bits;
+ BYTE *p_dst = dst_bits;
+ for(int x = 0; x < nWidth; x++) {
+ p_dst[FI_RGBA_RED] = p_src[0];
+ p_dst[FI_RGBA_GREEN] = p_src[1];
+ p_dst[FI_RGBA_BLUE] = p_src[2];
+ p_dst[FI_RGBA_ALPHA] = p_src[3];
+ p_src += nChannels;
+ p_dst += nChannels;
+ }
+ src_bits += src_pitch;
+ dst_bits -= dst_pitch;
+ }
+ Bitmap = dib;
+ }
+ }
+ else {
+ assert(false);// do nothing
+ }
+ }
+ // 32-bit / channel => undocumented HDR
+ // --------------------------------------------------------------
+ else if (32 == _headerInfo._BitsPerPixel) {
+ if (3 == nChannels) {
+ // RGBF 32-bit
+ FIBITMAP *dib = FreeImage_AllocateT(FIT_RGBF, nWidth, nHeight);
+ if (NULL != dib) {
+ // just copy buffer
+ BYTE *src_bits = (BYTE*)iprData;
+ BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1);
+ unsigned src_pitch = nChannels * nWidth * bytes;
+ unsigned dst_pitch = FreeImage_GetPitch(dib);
+ for(int y = 0; y < nHeight; y++) {
+ memcpy(dst_bits, src_bits, src_pitch);
+ src_bits += src_pitch;
+ dst_bits -= dst_pitch;
+ }
+ Bitmap = dib;
+ }
+ }
+ }
+ }
+ break;
+
+ case PSD_INDEXED: // Indexed
+ {
+ // iprData holds the indices of loop through the palette
+ assert(0 != _colourModeData._plColourData);
+ assert(768 == _colourModeData._Length);
+ assert(0 < _ColourCount);
+
+ // grey or palettised 8 bits
+ FIBITMAP *dib = FreeImage_Allocate(nWidth, nHeight, 8);
+ if (NULL != dib) {
+ // get the palette
+ if (_colourModeData.FillPalette(dib)) {
+ // copy buffer
+ BYTE *src_bits = (BYTE*)iprData;
+ BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1);
+ unsigned src_pitch = nChannels * nWidth * bytes;
+ unsigned dst_pitch = FreeImage_GetPitch(dib);
+ for(int y = 0; y < nHeight; y++) {
+ memcpy(dst_bits, src_bits, src_pitch);
+ src_bits += src_pitch;
+ dst_bits -= dst_pitch;
+ }
+ }
+ }
+ Bitmap = dib;
+ }
+ break;
+
+ case PSD_CMYK: // CMYK
+ {
+ float C, M, Y, K;
+ float s = 1.f / pow( 2.0f, _headerInfo._BitsPerPixel);
+
+ if (16 == _headerInfo._BitsPerPixel) {
+ // CMYK 16-bit : convert to RGB 16-bit
+ FIBITMAP *dib = FreeImage_AllocateT(FIT_RGB16, nWidth, nHeight);
+ if (NULL != dib) {
+ BYTE *src_bits = (BYTE*)iprData;
+ BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1);
+ unsigned src_pitch = nChannels * nWidth * bytes;
+ unsigned dst_pitch = FreeImage_GetPitch(dib);
+ for(int y = 0; y < nHeight; y++) {
+ unsigned short *src_line = (unsigned short*)src_bits;
+ FIRGB16 *dst_line = (FIRGB16*)dst_bits;
+ for(int x = 0; x < nWidth; x++) {
+ C = (1.f - (float)psdGetValue((BYTE*)&src_line[0], bytes ) * s );
+ M = (1.f - (float)psdGetValue((BYTE*)&src_line[1], bytes ) * s );
+ Y = (1.f - (float)psdGetValue((BYTE*)&src_line[2], bytes ) * s );
+ K = (1.f - (float)psdGetValue((BYTE*)&src_line[3], bytes ) * s );
+ CMYKToRGB16(C, M, Y, K, &dst_line[x]);
+ src_line += nChannels;
+ }
+ src_bits += src_pitch;
+ dst_bits -= dst_pitch;
+ }
+ Bitmap = dib;
+ }
+ }
+ else {
+ // CMYK 8-bit : convert to RGB 8-bit
+ FIBITMAP *dib = FreeImage_Allocate(nWidth, nHeight, 24);
+ if (NULL != dib) {
+ BYTE *src_bits = (BYTE*)iprData;
+ BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1);
+ unsigned src_pitch = nChannels * nWidth * bytes;
+ unsigned dst_pitch = FreeImage_GetPitch(dib);
+ for(int y = 0; y < nHeight; y++) {
+ BYTE *src_line = (BYTE*)src_bits;
+ RGBTRIPLE *dst_line = (RGBTRIPLE*)dst_bits;
+ for(int x = 0; x < nWidth; x++) {
+ C = (1.f - (float)psdGetValue((BYTE*)&src_line[0], bytes ) * s );
+ M = (1.f - (float)psdGetValue((BYTE*)&src_line[1], bytes ) * s );
+ Y = (1.f - (float)psdGetValue((BYTE*)&src_line[2], bytes ) * s );
+ K = (1.f - (float)psdGetValue((BYTE*)&src_line[3], bytes ) * s );
+ CMYKToRGB8(C, M, Y, K, &dst_line[x]);
+ src_line += nChannels;
+ }
+ src_bits += src_pitch;
+ dst_bits -= dst_pitch;
+ }
+ Bitmap = dib;
+ }
+ }
+ }
+ break;
+
+ case PSD_MULTICHANNEL: // Multichannel
+ {
+ // assume format is in either CMY or CMYK
+ assert(3 <= nChannels);
+ float C, M, Y, K;
+ float s = 1.f / pow( 2.0f, _headerInfo._BitsPerPixel);
+
+ if (16 == _headerInfo._BitsPerPixel) {
+ // CMY(K) 16-bit : convert to RGB 16-bit
+ FIBITMAP *dib = FreeImage_AllocateT(FIT_RGB16, nWidth, nHeight);
+ if (NULL != dib) {
+ BYTE *src_bits = (BYTE*)iprData;
+ BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1);
+ unsigned src_pitch = nChannels * nWidth * bytes;
+ unsigned dst_pitch = FreeImage_GetPitch(dib);
+ for(int y = 0; y < nHeight; y++) {
+ unsigned short *src_line = (unsigned short*)src_bits;
+ FIRGB16 *dst_line = (FIRGB16*)dst_bits;
+ for(int x = 0; x < nWidth; x++) {
+ C = (1.f - (float)psdGetValue((BYTE*)&src_line[0], bytes ) * s );
+ M = (1.f - (float)psdGetValue((BYTE*)&src_line[1], bytes ) * s );
+ Y = (1.f - (float)psdGetValue((BYTE*)&src_line[2], bytes ) * s );
+ K = (4 <= nChannels) ? (1.f - (float)psdGetValue((BYTE*)&src_line[nChannels], bytes )*s ) : 0;
+ CMYKToRGB16(C, M, Y, K, &dst_line[x]);
+ src_line += nChannels;
+ }
+ src_bits += src_pitch;
+ dst_bits -= dst_pitch;
+ }
+ Bitmap = dib;
+ }
+ }
+ else {
+ // CMY(K) 8-bit : convert to RGB 8-bit
+ FIBITMAP *dib = FreeImage_Allocate(nWidth, nHeight, 24);
+ if (NULL != dib) {
+ BYTE *src_bits = (BYTE*)iprData;
+ BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1);
+ unsigned src_pitch = nChannels * nWidth * bytes;
+ unsigned dst_pitch = FreeImage_GetPitch(dib);
+ for(int y = 0; y < nHeight; y++) {
+ BYTE *src_line = (BYTE*)src_bits;
+ RGBTRIPLE *dst_line = (RGBTRIPLE*)dst_bits;
+ for(int x = 0; x < nWidth; x++) {
+ C = (1.f - (float)psdGetValue((BYTE*)&src_line[0], bytes ) * s );
+ M = (1.f - (float)psdGetValue((BYTE*)&src_line[1], bytes ) * s );
+ Y = (1.f - (float)psdGetValue((BYTE*)&src_line[2], bytes ) * s );
+ K = (4 <= nChannels) ? (1.f - (float)psdGetValue((BYTE*)&src_line[nChannels], bytes )*s ) : 0;
+ CMYKToRGB8(C, M, Y, K, &dst_line[x]);
+ src_line += nChannels;
+ }
+ src_bits += src_pitch;
+ dst_bits -= dst_pitch;
+ }
+ Bitmap = dib;
+ }
+ }
+ }
+ break;
+
+ case PSD_LAB: // Lab
+ {
+ const unsigned dMaxColours = 1 << _headerInfo._BitsPerPixel;
+ const float sL = 100.F / dMaxColours;
+ const float sa = 256.F / dMaxColours;
+ const float sb = 256.F / dMaxColours;
+ float L, a, b;
+
+ if (16 == _headerInfo._BitsPerPixel) {
+ // CIE Lab 16-bit : convert to RGB 16-bit
+ FIBITMAP *dib = FreeImage_AllocateT(FIT_RGB16, nWidth, nHeight);
+ if (NULL != dib) {
+ BYTE *src_bits = (BYTE*)iprData;
+ BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1);
+ unsigned src_pitch = nChannels * nWidth * bytes;
+ unsigned dst_pitch = FreeImage_GetPitch(dib);
+ for(int y = 0; y < nHeight; y++) {
+ unsigned short *src_line = (unsigned short*)src_bits;
+ FIRGB16 *dst_line = (FIRGB16*)dst_bits;
+ for(int x = 0; x < nWidth; x++) {
+ L = (float)psdGetValue((BYTE*)&src_line[0], bytes ) * sL;
+ a = (float)psdGetValue((BYTE*)&src_line[1], bytes ) * sa - 128.F;
+ b = (float)psdGetValue((BYTE*)&src_line[2], bytes ) * sb - 128.F;
+ CIELabToRGB16(L, a, b, &dst_line[x]);
+ src_line += nChannels;
+ }
+ src_bits += src_pitch;
+ dst_bits -= dst_pitch;
+ }
+ Bitmap = dib;
+ }
+ } else {
+ // CIE Lab 8-bit : convert to RGB 8-bit
+ FIBITMAP *dib = FreeImage_Allocate(nWidth, nHeight, 24);
+ if (NULL != dib) {
+ BYTE *src_bits = (BYTE*)iprData;
+ BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, nHeight-1);
+ unsigned src_pitch = nChannels * nWidth * bytes;
+ unsigned dst_pitch = FreeImage_GetPitch(dib);
+ for(int y = 0; y < nHeight; y++) {
+ BYTE *src_line = (BYTE*)src_bits;
+ RGBTRIPLE *dst_line = (RGBTRIPLE*)dst_bits;
+ for(int x = 0; x < nWidth; x++) {
+ L = (float)psdGetValue((BYTE*)&src_line[0], bytes ) * sL;
+ a = (float)psdGetValue((BYTE*)&src_line[1], bytes ) * sa - 128.F;
+ b = (float)psdGetValue((BYTE*)&src_line[2], bytes ) * sb - 128.F;
+ CIELabToRGB8(L, a, b, &dst_line[x]);
+ src_line += nChannels;
+ }
+ src_bits += src_pitch;
+ dst_bits -= dst_pitch;
+ }
+ Bitmap = dib;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return Bitmap;
+}
+
+FIBITMAP* psdParser::ReadImageData(FreeImageIO *io, fi_handle handle) {
+ FIBITMAP *Bitmap = NULL;
+
+ if(handle != NULL) {
+ BYTE ShortValue[2];
+ int n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle);
+ short nCompression = (short)psdGetValue( ShortValue, sizeof(ShortValue) );
+
+ switch ( nCompression ) {
+ case PSD_COMPRESSION_NONE: // raw data
+ {
+ int nWidth = _headerInfo._Width;
+ int nHeight = _headerInfo._Height;
+ int bytes = _headerInfo._BitsPerPixel / 8;
+
+ int nPixels = nWidth * nHeight;
+ int nTotalBytes = nPixels * bytes * _headerInfo._Channels;
+
+ if(_headerInfo._BitsPerPixel == 1) {
+ // special case for PSD_BITMAP mode
+ bytes = 1;
+ nWidth = (nWidth + 7) / 8;
+ nWidth = ( nWidth > 0 ) ? nWidth : 1;
+ nPixels = nWidth * nHeight;
+ nTotalBytes = nWidth * nHeight;
+ }
+
+ BYTE * plData = 0;
+ BYTE * plPixel = 0;
+
+ int nBytes = 0;
+
+ switch (_headerInfo._ColourMode) {
+ case PSD_BITMAP:
+ {
+ plData = new BYTE [nTotalBytes];
+ plPixel = new BYTE [bytes];
+
+ while(nBytes < nTotalBytes) {
+ n = (int)io->read_proc(plPixel, bytes, 1, handle);
+ memcpy(plData+nBytes, plPixel, bytes );
+ nBytes += n * bytes;
+ }
+ SAFE_DELETE_ARRAY(plPixel);
+ }
+ break;
+
+ case PSD_INDEXED: // Indexed
+ {
+ assert( (-1 != _ColourCount) && (0 < _ColourCount) );
+ assert( NULL != _colourModeData._plColourData );
+
+ plData = new BYTE [nTotalBytes];
+ plPixel = new BYTE [bytes];
+
+ while(nBytes < nTotalBytes) {
+ n = (int)io->read_proc(plPixel, bytes, 1, handle);
+ memcpy(plData+nBytes, plPixel, bytes );
+ nBytes += n * bytes;
+ }
+ SAFE_DELETE_ARRAY(plPixel);
+ }
+ break;
+
+ case PSD_GRAYSCALE: // Grayscale
+ case PSD_DUOTONE: // Duotone
+ case PSD_RGB: // RGB
+ {
+ plData = new BYTE [nTotalBytes];
+ plPixel = new BYTE [bytes];
+ int nPixelCounter = 0;
+ int nChannels = _headerInfo._Channels;
+
+ for(int c = 0; c < nChannels; c++) {
+ nPixelCounter = c * bytes;
+ for(int nPos = 0; nPos < nPixels; ++nPos) {
+ n = (int)io->read_proc(plPixel, bytes, 1, handle);
+ if(n == 0) {
+ break;
+ }
+ if(2 == bytes) {
+ // swap for uint16
+ SwapShort((WORD*)&plPixel[0]);
+ } else if(4 == bytes) {
+ // swap for float
+ SwapLong((DWORD*)&plPixel[0]);
+ }
+ memcpy( plData + nPixelCounter, plPixel, bytes );
+ nBytes += n * bytes;
+ nPixelCounter += nChannels*bytes;
+ }
+ }
+ SAFE_DELETE_ARRAY(plPixel);
+ }
+ break;
+
+ case PSD_CMYK: // CMYK
+ case PSD_MULTICHANNEL: // Multichannel
+ {
+ plPixel = new BYTE[bytes];
+ plData = new BYTE[nTotalBytes];
+
+ int nPixelCounter = 0;
+ for (int c=0; c<_headerInfo._Channels; c++) {
+ nPixelCounter = c*bytes;
+ for ( int nPos = 0; nPos < nPixels; ++nPos ) {
+ n = (int)io->read_proc(plPixel, bytes, 1, handle);
+ if(n == 0) {
+ break;
+ }
+ memcpy(plData + nPixelCounter, plPixel, bytes );
+ nBytes += n * bytes;
+
+ nPixelCounter += _headerInfo._Channels*bytes;
+ }
+ }
+ SAFE_DELETE_ARRAY(plPixel);
+ }
+ break;
+
+ case PSD_LAB: // Lab
+ {
+ plPixel = new BYTE[bytes];
+ plData = new BYTE[nTotalBytes];
+ int nPixelCounter = 0;
+ for(int c = 0; c < 3; c++) {
+ nPixelCounter = c*bytes;
+ for ( int nPos = 0; nPos < nPixels; ++nPos ) {
+ n = (int)io->read_proc(plPixel, bytes, 1, handle);
+ if(n == 0) {
+ break;
+ }
+ memcpy(plData + nPixelCounter, plPixel, bytes);
+ nBytes += n * bytes;
+ nPixelCounter += 3*bytes;
+ }
+ }
+ SAFE_DELETE_ARRAY(plPixel);
+ }
+ break;
+ }
+
+ assert( nBytes == nTotalBytes );
+ if (nBytes == nTotalBytes) {
+ if (plData) {
+ switch (_headerInfo._BitsPerPixel) {
+ case 1:
+ case 8:
+ case 16:
+ case 32:
+ Bitmap = ProcessBuffer(plData);
+ break;
+
+ default: // Unsupported
+ break;
+ }
+ }
+ }
+
+ SAFE_DELETE_ARRAY(plData);
+ }
+ break;
+
+
+ case PSD_COMPRESSION_RLE: // RLE compression
+ {
+ int nWidth = _headerInfo._Width;
+ int nHeight = _headerInfo._Height;
+ int bytes = _headerInfo._BitsPerPixel / 8;
+
+ int nPixels = nWidth * nHeight;
+ int nTotalBytes = nPixels * bytes * _headerInfo._Channels;
+
+ if(_headerInfo._BitsPerPixel == 1) {
+ // special case for PSD_BITMAP mode
+ bytes = 1;
+ nWidth = (nWidth + 7) / 8;
+ nWidth = ( nWidth > 0 ) ? nWidth : 1;
+ nPixels = nWidth * nHeight;
+ nTotalBytes = nWidth * nHeight;
+ }
+
+ BYTE * plData = new BYTE[nTotalBytes];
+ BYTE * p = plData;
+ int nValue = 0;
+
+ BYTE ByteValue[1];
+
+ int Count = 0;
+
+ // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data,
+ // which we're going to just skip.
+ io->seek_proc(handle, nHeight * _headerInfo._Channels * 2, SEEK_CUR);
+
+ for (int channel = 0; channel < _headerInfo._Channels; channel++) {
+ // Read the RLE data.
+ Count = 0;
+ while (Count < nPixels) {
+ io->read_proc(&ByteValue, sizeof(ByteValue), 1, handle);
+
+ int len = psdGetValue( ByteValue, sizeof(ByteValue) );
+ if ( 128 > len ) {
+ len++;
+ Count += len;
+
+ while (len) {
+ io->read_proc(&ByteValue, sizeof(ByteValue), 1, handle);
+ nValue = psdGetValue( ByteValue, sizeof(ByteValue) );
+ *p = (BYTE)nValue;
+ p += sizeof(ByteValue);
+ len--;
+ }
+ }
+ else if ( 128 < len ) {
+ // Next -len+1 bytes in the dest are replicated from next source byte.
+ // (Interpret len as a negative 8-bit int.)
+ len ^= 0x0FF;
+ len += 2;
+ io->read_proc(&ByteValue, sizeof(ByteValue), 1, handle);
+
+ nValue = psdGetValue( ByteValue, sizeof(ByteValue) );
+ Count += len;
+ while (len) {
+ *p = (BYTE)nValue;
+ p += sizeof(ByteValue);
+ len--;
+ }
+ }
+ else if ( 128 == len ) {
+ // Do nothing
+ }
+ }
+ }
+
+ BYTE * prSource = plData;
+ BYTE * plDest = new BYTE[nTotalBytes];
+ memset(plDest, 254, nTotalBytes);
+
+ int nPixelCounter = 0;
+ for(int c=0; c<_headerInfo._Channels; c++) {
+ nPixelCounter = c*bytes;
+ for (int nPos = 0; nPos<nPixels; ++nPos) {
+ memcpy( plDest + nPixelCounter, prSource, bytes );
+ prSource++;
+ nPixelCounter += _headerInfo._Channels*bytes;
+ }
+ }
+ SAFE_DELETE_ARRAY(plData);
+
+ if (plDest) {
+ switch (_headerInfo._BitsPerPixel) {
+ case 1:
+ case 8:
+ case 16:
+ Bitmap = ProcessBuffer(plDest);
+ break;
+
+ default: // Unsupported format
+ break;
+ }
+ }
+ SAFE_DELETE_ARRAY(plDest);
+ }
+ break;
+
+ case 2: // ZIP without prediction, no specification
+ break;
+
+ case 3: // ZIP with prediction, no specification
+ break;
+
+ default: // Unknown format
+ break;
+ }
+ }
+
+ return Bitmap;
+
+}
+
+FIBITMAP* psdParser::Load(FreeImageIO *io, fi_handle handle, int s_format_id) {
+ FIBITMAP *Bitmap = NULL;
+
+ 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 (!ReadImageResource(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
+ if(NULL != _iccProfile._ProfileData) {
+ FreeImage_CreateICCProfile(Bitmap, _iccProfile._ProfileData, _iccProfile._ProfileSize);
+ }
+
+ } catch(const char *text) {
+ FreeImage_OutputMessageProc(s_format_id, text);
+ }
+
+ return Bitmap;
+}