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 )