Alien-FreeImage
view release on metacpan or search on metacpan
src/Source/FreeImage/MNGHelper.cpp view on Meta::CPAN
}
inline void
mng_SwapShort(WORD *sp) {
#ifndef FREEIMAGE_BIGENDIAN
SwapShort(sp);
#endif
}
inline void
mng_SwapLong(DWORD *lp) {
#ifndef FREEIMAGE_BIGENDIAN
SwapLong(lp);
#endif
}
/**
Returns the size, in bytes, of a FreeImageIO stream, from the current position.
*/
static long
mng_LOF(FreeImageIO *io, fi_handle handle) {
long start_pos = io->tell_proc(handle);
io->seek_proc(handle, 0, SEEK_END);
long file_length = io->tell_proc(handle);
io->seek_proc(handle, start_pos, SEEK_SET);
return file_length;
}
/**
Count the number of bytes in a PNG stream, from IHDR to IEND.
If successful, the stream position, as given by io->tell_proc(handle),
should be the end of the PNG stream at the return of the function.
@param io
@param handle
@param inPos
@param m_TotalBytesOfChunks
@return Returns TRUE if successful, returns FALSE otherwise
*/
static BOOL
mng_CountPNGChunks(FreeImageIO *io, fi_handle handle, long inPos, unsigned *m_TotalBytesOfChunks) {
long mLOF;
long mPos;
BOOL mEnd = FALSE;
DWORD mLength = 0;
BYTE mChunkName[5];
*m_TotalBytesOfChunks = 0;
// get the length of the file
mLOF = mng_LOF(io, handle);
// go to the start of the file
io->seek_proc(handle, inPos, SEEK_SET);
try {
// parse chunks
while(mEnd == FALSE) {
// chunk length
mPos = io->tell_proc(handle);
if(mPos + 4 > mLOF) {
throw(1);
}
io->read_proc(&mLength, 1, 4, handle);
mng_SwapLong(&mLength);
// chunk name
mPos = io->tell_proc(handle);
if(mPos + 4 > mLOF) {
throw(1);
}
io->read_proc(&mChunkName[0], 1, 4, handle);
mChunkName[4] = '\0';
// go to next chunk
mPos = io->tell_proc(handle);
// 4 = size of the CRC
if(mPos + (long)mLength + 4 > mLOF) {
throw(1);
}
io->seek_proc(handle, mLength + 4, SEEK_CUR);
switch( mng_GetChunckType(mChunkName) ) {
case IHDR:
if(mLength != 13) {
throw(1);
}
break;
case IEND:
mEnd = TRUE;
// the length below includes 4 bytes CRC, but no bytes for Length
*m_TotalBytesOfChunks = io->tell_proc(handle) - inPos;
break;
case UNKNOWN_CHUNCK:
default:
break;
}
} // while(!mEnd)
return TRUE;
} catch(int) {
return FALSE;
}
}
/**
Retrieve the position of a chunk in a PNG stream
@param hPngMemory PNG stream handle
@param chunk_name Name of the chunk to be found
@param offset Start of the search in the stream
@param start_pos [returned value] Start position of the chunk
@param next_pos [returned value] Start position of the next chunk
@return Returns TRUE if successful, returns FALSE otherwise
*/
static BOOL
mng_FindChunk(FIMEMORY *hPngMemory, BYTE *chunk_name, long offset, DWORD *start_pos, DWORD *next_pos) {
DWORD mLength = 0;
BYTE *data = NULL;
DWORD size_in_bytes = 0;
*start_pos = 0;
*next_pos = 0;
// get a pointer to the stream buffer
FreeImage_AcquireMemory(hPngMemory, &data, &size_in_bytes);
if(!(data && size_in_bytes) || (size_in_bytes < 20) || (size_in_bytes - offset < 20)) {
// not enough space to read a signature(8 bytes) + a chunk(at least 12 bytes)
return FALSE;
}
try {
// skip the signature and/or any following chunk(s)
DWORD chunk_pos = offset;
while(1) {
// get chunk length
if(chunk_pos + 4 > size_in_bytes) {
break;
}
src/Source/FreeImage/MNGHelper.cpp view on Meta::CPAN
FIMEMORY *hPngMemory = NULL;
FIMEMORY *hIDATMemory = NULL;
// ---
DWORD jng_width = 0;
DWORD jng_height = 0;
BYTE jng_color_type = 0;
BYTE jng_image_sample_depth = 0;
BYTE jng_image_compression_method = 0;
BYTE jng_alpha_sample_depth = 0;
BYTE jng_alpha_compression_method = 0;
BYTE jng_alpha_filter_method = 0;
BYTE jng_alpha_interlace_method = 0;
DWORD mng_frame_width = 0;
DWORD mng_frame_height = 0;
DWORD mng_ticks_per_second = 0;
DWORD mng_nominal_layer_count = 0;
DWORD mng_nominal_frame_count = 0;
DWORD mng_nominal_play_time = 0;
DWORD mng_simplicity_profile = 0;
DWORD res_x = 2835; // 72 dpi
DWORD res_y = 2835; // 72 dpi
RGBQUAD rgbBkColor = {0, 0, 0, 0};
WORD bk_red, bk_green, bk_blue;
BOOL hasBkColor = FALSE;
BOOL mHasIDAT = FALSE;
tEXtMAP key_value_pair;
// ---
BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
// get the file size
const long mLOF = mng_LOF(io, handle);
// go to the first chunk
io->seek_proc(handle, Offset, SEEK_SET);
try {
BOOL mEnd = FALSE;
while(mEnd == FALSE) {
// start of the chunk
LastOffset = io->tell_proc(handle);
// read length
mLength = 0;
io->read_proc(&mLength, 1, sizeof(mLength), handle);
mng_SwapLong(&mLength);
// read name
io->read_proc(&mChunkName[0], 1, 4, handle);
mChunkName[4] = '\0';
if(mLength > 0) {
mChunk = (BYTE*)realloc(mChunk, mLength);
if(!mChunk) {
FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: out of memory", mChunkName);
throw (const char*)NULL;
}
Offset = io->tell_proc(handle);
if(Offset + (long)mLength > mLOF) {
FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: unexpected end of file", mChunkName);
throw (const char*)NULL;
}
// read chunk
io->read_proc(mChunk, 1, mLength, handle);
}
// read crc
io->read_proc(&crc_file, 1, sizeof(crc_file), handle);
mng_SwapLong(&crc_file);
// check crc
DWORD crc_check = FreeImage_ZLibCRC32(0, &mChunkName[0], 4);
crc_check = FreeImage_ZLibCRC32(crc_check, mChunk, mLength);
if(crc_check != crc_file) {
FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: bad CRC", mChunkName);
throw (const char*)NULL;
}
switch( mng_GetChunckType(mChunkName) ) {
case MHDR:
// The MHDR chunk is always first in all MNG datastreams except for those
// that consist of a single PNG or JNG datastream with a PNG or JNG signature.
if(mLength == 28) {
memcpy(&mng_frame_width, &mChunk[0], 4);
memcpy(&mng_frame_height, &mChunk[4], 4);
memcpy(&mng_ticks_per_second, &mChunk[8], 4);
memcpy(&mng_nominal_layer_count, &mChunk[12], 4);
memcpy(&mng_nominal_frame_count, &mChunk[16], 4);
memcpy(&mng_nominal_play_time, &mChunk[20], 4);
memcpy(&mng_simplicity_profile, &mChunk[24], 4);
mng_SwapLong(&mng_frame_width);
mng_SwapLong(&mng_frame_height);
mng_SwapLong(&mng_ticks_per_second);
mng_SwapLong(&mng_nominal_layer_count);
mng_SwapLong(&mng_nominal_frame_count);
mng_SwapLong(&mng_nominal_play_time);
mng_SwapLong(&mng_simplicity_profile);
} else {
FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: size is %d instead of 28", mChunkName, mLength);
}
break;
case MEND:
mEnd = TRUE;
break;
case LOOP:
case ENDL:
break;
case DEFI:
break;
case SAVE:
case SEEK:
case TERM:
break;
case BACK:
break;
// Global "PLTE" and "tRNS" (if any). PNG "PLTE" will be of 0 byte, as it uses global data.
case PLTE: // Global
m_HasGlobalPalette = TRUE;
PLTE_file_size = mLength + 12; // (lentgh, name, array, crc) = (4, 4, mLength, 4)
PLTE_file_chunk = (BYTE*)realloc(PLTE_file_chunk, PLTE_file_size);
if(!PLTE_file_chunk) {
FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: out of memory", mChunkName);
throw (const char*)NULL;
} else {
mOrigPos = io->tell_proc(handle);
// seek to the start of the chunk
io->seek_proc(handle, LastOffset, SEEK_SET);
// load the whole chunk
io->read_proc(PLTE_file_chunk, 1, PLTE_file_size, handle);
// go to the start of the next chunk
io->seek_proc(handle, mOrigPos, SEEK_SET);
}
break;
case tRNS: // Global
break;
case IHDR:
Offset = LastOffset;
// parse the PNG file and get its file size
if(mng_CountPNGChunks(io, handle, Offset, &m_TotalBytesOfChunks) == FALSE) {
// reach an unexpected end of file
mEnd = TRUE;
FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: unexpected end of PNG file", mChunkName);
break;
}
// wrap the { IHDR, ..., IEND } chunks as a PNG stream
if(hPngMemory == NULL) {
hPngMemory = FreeImage_OpenMemory();
}
mOrigPos = io->tell_proc(handle);
// write PNG file signature
FreeImage_SeekMemory(hPngMemory, 0, SEEK_SET);
FreeImage_WriteMemory(g_png_signature, 1, 8, hPngMemory);
mChunk = (BYTE*)realloc(mChunk, m_TotalBytesOfChunks);
if(!mChunk) {
FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: out of memory", mChunkName);
throw (const char*)NULL;
}
// on calling CountPNGChunks earlier, we were in Offset pos,
// go back there
io->seek_proc(handle, Offset, SEEK_SET);
io->read_proc(mChunk, 1, m_TotalBytesOfChunks, handle);
// Put back to original pos
io->seek_proc(handle, mOrigPos, SEEK_SET);
// write the PNG chunks
FreeImage_WriteMemory(mChunk, 1, m_TotalBytesOfChunks, hPngMemory);
// plug in global PLTE if local PLTE exists
if(m_HasGlobalPalette) {
// ensure we remove some local chunks, so that global
// "PLTE" can be inserted right before "IDAT".
mng_RemoveChunk(hPngMemory, mng_PLTE);
mng_RemoveChunk(hPngMemory, mng_tRNS);
mng_RemoveChunk(hPngMemory, mng_bKGD);
// insert global "PLTE" chunk in its entirety before "IDAT"
mng_InsertChunk(hPngMemory, mng_IDAT, PLTE_file_chunk, PLTE_file_size);
}
if(dib) FreeImage_Unload(dib);
dib = mng_LoadFromMemoryHandle(hPngMemory, flags);
// stop after the first image
mEnd = TRUE;
break;
case JHDR:
if(mLength == 16) {
memcpy(&jng_width, &mChunk[0], 4);
memcpy(&jng_height, &mChunk[4], 4);
mng_SwapLong(&jng_width);
mng_SwapLong(&jng_height);
jng_color_type = mChunk[8];
jng_image_sample_depth = mChunk[9];
jng_image_compression_method = mChunk[10];
//BYTE jng_image_interlace_method = mChunk[11]; // for debug only
jng_alpha_sample_depth = mChunk[12];
jng_alpha_compression_method = mChunk[13];
jng_alpha_filter_method = mChunk[14];
jng_alpha_interlace_method = mChunk[15];
} else {
FreeImage_OutputMessageProc(format_id, "Error while parsing %s chunk: invalid chunk length", mChunkName);
throw (const char*)NULL;
}
break;
case JDAT:
if(hJpegMemory == NULL) {
hJpegMemory = FreeImage_OpenMemory();
}
// as there may be several JDAT chunks, concatenate them
FreeImage_WriteMemory(mChunk, 1, mLength, hJpegMemory);
break;
case IDAT:
if(!header_only && (jng_alpha_compression_method == 0)) {
// PNG grayscale IDAT format
if(hIDATMemory == NULL) {
hIDATMemory = FreeImage_OpenMemory();
mHasIDAT = TRUE;
}
// as there may be several IDAT chunks, concatenate them
FreeImage_WriteMemory(mChunk, 1, mLength, hIDATMemory);
}
break;
case IEND:
if(!hJpegMemory) {
mEnd = TRUE;
break;
}
// load the JPEG
if(dib) {
FreeImage_Unload(dib);
}
dib = mng_LoadFromMemoryHandle(hJpegMemory, flags);
// load the PNG alpha layer
if(mHasIDAT) {
BYTE *data = NULL;
DWORD size_in_bytes = 0;
// get a pointer to the IDAT buffer
FreeImage_AcquireMemory(hIDATMemory, &data, &size_in_bytes);
if(data && size_in_bytes) {
// wrap the IDAT chunk as a PNG stream
if(hPngMemory == NULL) {
hPngMemory = FreeImage_OpenMemory();
}
mng_WritePNGStream(jng_width, jng_height, jng_alpha_sample_depth, data, size_in_bytes, hPngMemory);
// load the PNG
if(dib_alpha) {
FreeImage_Unload(dib_alpha);
}
dib_alpha = mng_LoadFromMemoryHandle(hPngMemory, flags);
}
}
// stop the parsing
mEnd = TRUE;
break;
case JDAA:
break;
src/Source/FreeImage/MNGHelper.cpp view on Meta::CPAN
}
unsigned bpp = FreeImage_GetBPP(dib);
switch(bpp) {
case 8:
if(FreeImage_GetColorType(dib) == FIC_MINISBLACK) {
dib_rgb = dib;
jng_color_type = MNG_COLORTYPE_JPEGGRAY;
} else {
// JPEG plugin will convert other types (FIC_MINISWHITE, FIC_PALETTE) to 24-bit on the fly
//dib_rgb = FreeImage_ConvertTo24Bits(dib);
dib_rgb = dib;
jng_color_type = MNG_COLORTYPE_JPEGCOLOR;
}
break;
case 24:
dib_rgb = dib;
jng_color_type = MNG_COLORTYPE_JPEGCOLOR;
break;
case 32:
dib_rgb = FreeImage_ConvertTo24Bits(dib);
jng_color_type = MNG_COLORTYPE_JPEGCOLORA;
jng_alpha_sample_depth = 8;
break;
default:
return FALSE;
}
jng_width = (DWORD)FreeImage_GetWidth(dib);
jng_height = (DWORD)FreeImage_GetHeight(dib);
try {
hJngMemory = FreeImage_OpenMemory();
// --- write JNG file signature ---
FreeImage_WriteMemory(g_jng_signature, 1, 8, hJngMemory);
// --- write a JHDR chunk ---
SwapLong(&jng_width);
SwapLong(&jng_height);
memcpy(&buffer[0], &jng_width, 4);
memcpy(&buffer[4], &jng_height, 4);
SwapLong(&jng_width);
SwapLong(&jng_height);
buffer[8] = jng_color_type;
buffer[9] = jng_image_sample_depth;
buffer[10] = jng_image_compression_method;
buffer[11] = jng_image_interlace_method;
buffer[12] = jng_alpha_sample_depth;
buffer[13] = jng_alpha_compression_method;
buffer[14] = jng_alpha_filter_method;
buffer[15] = jng_alpha_interlace_method;
mng_WriteChunk(mng_JHDR, &buffer[0], 16, hJngMemory);
// --- write a sequence of JDAT chunks ---
hJpegMemory = FreeImage_OpenMemory();
flags |= JPEG_BASELINE;
if(!FreeImage_SaveToMemory(FIF_JPEG, dib_rgb, hJpegMemory, flags)) {
throw (const char*)NULL;
}
if(dib_rgb != dib) {
FreeImage_Unload(dib_rgb);
dib_rgb = NULL;
}
{
BYTE *jpeg_data = NULL;
DWORD size_in_bytes = 0;
// get a pointer to the stream buffer
FreeImage_AcquireMemory(hJpegMemory, &jpeg_data, &size_in_bytes);
// write chunks
for(DWORD k = 0; k < size_in_bytes;) {
DWORD bytes_left = size_in_bytes - k;
DWORD chunk_size = MIN(JPEG_CHUNK_SIZE, bytes_left);
mng_WriteChunk(mng_JDAT, &jpeg_data[k], chunk_size, hJngMemory);
k += chunk_size;
}
}
FreeImage_CloseMemory(hJpegMemory);
hJpegMemory = NULL;
// --- write alpha layer as a sequence of IDAT chunk ---
if((bpp == 32) && (jng_color_type == MNG_COLORTYPE_JPEGCOLORA)) {
dib_alpha = FreeImage_GetChannel(dib, FICC_ALPHA);
hPngMemory = FreeImage_OpenMemory();
if(!FreeImage_SaveToMemory(FIF_PNG, dib_alpha, hPngMemory, PNG_DEFAULT)) {
throw (const char*)NULL;
}
FreeImage_Unload(dib_alpha);
dib_alpha = NULL;
// get the IDAT chunk
{
BOOL bResult = FALSE;
DWORD start_pos = 0;
DWORD next_pos = 0;
long offset = 8;
do {
// find the next IDAT chunk from 'offset' position
bResult = mng_FindChunk(hPngMemory, mng_IDAT, offset, &start_pos, &next_pos);
if(!bResult) break;
BYTE *png_data = NULL;
DWORD size_in_bytes = 0;
// get a pointer to the stream buffer
FreeImage_AcquireMemory(hPngMemory, &png_data, &size_in_bytes);
// write the IDAT chunk
mng_WriteChunk(mng_IDAT, &png_data[start_pos+8], next_pos - start_pos - 12, hJngMemory);
offset = next_pos;
} while(bResult);
}
FreeImage_CloseMemory(hPngMemory);
hPngMemory = NULL;
}
// --- write a IEND chunk ---
mng_WriteChunk(mng_IEND, NULL, 0, hJngMemory);
// write the JNG on output stream
{
BYTE *jng_data = NULL;
DWORD size_in_bytes = 0;
FreeImage_AcquireMemory(hJngMemory, &jng_data, &size_in_bytes);
io->write_proc(jng_data, 1, size_in_bytes, handle);
}
FreeImage_CloseMemory(hJngMemory);
FreeImage_CloseMemory(hJpegMemory);
FreeImage_CloseMemory(hPngMemory);
return TRUE;
} catch(const char *text) {
FreeImage_CloseMemory(hJngMemory);
FreeImage_CloseMemory(hJpegMemory);
FreeImage_CloseMemory(hPngMemory);
if(dib_rgb && (dib_rgb != dib)) {
FreeImage_Unload(dib_rgb);
}
FreeImage_Unload(dib_alpha);
if(text) {
FreeImage_OutputMessageProc(format_id, text);
}
( run in 0.577 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )