Пример #1
0
// Sends an ImageServer frame
// [ImageType(1 byte) ImageSize(4 bytes) ImageData(n bytes)]
int transmitFrame(FIMEMORY *fiBuffer, SOCKET &clientSocket, unsigned char imageType) {
	int socketStatus;
	u_long imageSize;
	BYTE *fiBufferPtr = NULL;
	DWORD fiBufferSize = 0;

	// Get pointer to buffer memory
	socketStatus = FreeImage_AcquireMemory(fiBuffer, &fiBufferPtr, &fiBufferSize);
	if (socketStatus != 1) return SOCKET_ERROR;

	// Send the image type
	socketStatus = send(clientSocket, (char*)&imageType, 1, 0);
	if (socketStatus != 1) return socketStatus;

	// Send the image size (in bytes)
	imageSize = htonl((u_long)fiBufferSize);
	socketStatus = send(clientSocket, (char*)&imageSize, 4, 0);
	if (socketStatus != 4) return socketStatus;

	// Send the image
	socketStatus = send(clientSocket, (char*)fiBufferPtr, fiBufferSize, 0);
	if (socketStatus != fiBufferSize) return socketStatus;
	/*
	char msg[1024];
	sprintf_s(msg, 1024, "imageType: %i imageSize: %i", imageType, imageSize);
	MessageBox(NULL,msg,"ADES DEBUG", MB_OK);
	*/
	return socketStatus;
}
Пример #2
0
// 独立函数,读取gif图片,写白背景,转为PNG并写入缓存,返回缓存地址
FOX_DLL FIMEMORY * gif2png_bufopen(char *gifpath, BYTE ** buffpointeraddr, DWORD * bufflenaddr)
{
	FIBITMAP * hImage ;
	RGBQUAD * pal ;
	FIMEMORY * hMemory = NULL ;
	BYTE *mem_buffer = NULL ;
	DWORD size_in_bytes = 0 ;

	hImage = FreeImage_Load(FIF_GIF, gifpath, 0);

	pal = FreeImage_GetPalette(hImage);
	pal[70].rgbRed = 255 ;
	pal[70].rgbGreen = 255 ;
	pal[70].rgbBlue = 255 ;
	FreeImage_SetTransparent(hImage, false);

	hMemory = FreeImage_OpenMemory() ;
	FreeImage_SaveToMemory(FIF_PNG, hImage, hMemory, PNG_DEFAULT) ;
	FreeImage_Unload(hImage) ;

	FreeImage_AcquireMemory(hMemory, &mem_buffer, &size_in_bytes);
	*buffpointeraddr = mem_buffer ;
	*bufflenaddr = size_in_bytes ;
	
	return hMemory ;
//	FreeImage_CloseMemory(hMemory) ; // 使用完缓存记得要释放
}
Пример #3
0
static BlockReference* 
FreeImage_SavePageToBlock(MULTIBITMAPHEADER *header, FIBITMAP *data) {
	if (header->read_only || !header->locked_pages.empty())
		return NULL;

	DWORD compressed_size = 0;
	BYTE *compressed_data = NULL;

	// compress the bitmap data

	// open a memory handle
	FIMEMORY *hmem = FreeImage_OpenMemory();
	if(hmem==NULL) return NULL;
	// save the file to memory
	if(!FreeImage_SaveToMemory(header->cache_fif, data, hmem, 0)) {
		FreeImage_CloseMemory(hmem);
		return NULL;
	}
	// get the buffer from the memory stream
	if(!FreeImage_AcquireMemory(hmem, &compressed_data, &compressed_size)) {
		FreeImage_CloseMemory(hmem);
		return NULL;
	}

	// write the compressed data to the cache
	int ref = header->m_cachefile->writeFile(compressed_data, compressed_size);
	// get rid of the compressed data
	FreeImage_CloseMemory(hmem);

	return new(std::nothrow) BlockReference(ref, compressed_size);
}
Пример #4
0
    //---------------------------------------------------------------------
    DataStreamPtr FreeImageCodec::code(MemoryDataStreamPtr& input, Codec::CodecDataPtr& pData) const
    {        
		// Set error handler
		FreeImage_SetOutputMessage(FreeImageSaveErrorHandler);

		FIBITMAP* fiBitmap = encode(input, pData);

		// open memory chunk allocated by FreeImage
		FIMEMORY* mem = FreeImage_OpenMemory();
		// write data into memory
		FreeImage_SaveToMemory((FREE_IMAGE_FORMAT)mFreeImageType, fiBitmap, mem);
		// Grab data information
		BYTE* data;
		DWORD size;
		FreeImage_AcquireMemory(mem, &data, &size);
		// Copy data into our own buffer
		// Because we're asking MemoryDataStream to free this, must create in a compatible way
		BYTE* ourData = OGRE_ALLOC_T(BYTE, size, MEMCATEGORY_GENERAL);
		memcpy(ourData, data, size);
		// Wrap data in stream, tell it to free on close 
		DataStreamPtr outstream(OGRE_NEW MemoryDataStream(ourData, size, true));
		// Now free FreeImage memory buffers
		FreeImage_CloseMemory(mem);
		// Unload bitmap
		FreeImage_Unload(fiBitmap);

		return outstream;


    }
Пример #5
0
    //---------------------------------------------------------------------
    DataStreamPtr FreeImageCodec::code(MemoryDataStreamPtr& input, Codec::CodecDataPtr& pData) const
    {        
		FIBITMAP* fiBitmap = encode(input, pData);

		// open memory chunk allocated by FreeImage
		FIMEMORY* mem = FreeImage_OpenMemory();
		// write data into memory
		FreeImage_SaveToMemory((FREE_IMAGE_FORMAT)mFreeImageType, fiBitmap, mem);
		// Grab data information
		BYTE* data;
		DWORD size;
		FreeImage_AcquireMemory(mem, &data, &size);
		// Copy data into our own buffer
		BYTE* ourData = new BYTE[size];
		memcpy(ourData, data, size);
		// Wrap data in stream, tell it to free on close 
		DataStreamPtr outstream(new MemoryDataStream(ourData, size, true));
		// Now free FreeImage memory buffers
		FreeImage_CloseMemory(mem);
		// Unload bitmap
		FreeImage_Unload(fiBitmap);

		return outstream;


    }
Пример #6
0
void testAcquireMemIO(const char *lpszPathName) {
    FIMEMORY *hmem = NULL;

    // load a regular file
    FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(lpszPathName);
    FIBITMAP *dib = FreeImage_Load(fif, lpszPathName, 0);

    // open and allocate a memory stream
    hmem = FreeImage_OpenMemory();

    // save the file to memory
    FreeImage_SaveToMemory(FIF_PNG, dib, hmem, PNG_DEFAULT);

    FreeImage_Unload(dib);

    // get the buffer from the memory stream
    BYTE *mem_buffer = NULL;
    DWORD size_in_bytes = 0;

    FreeImage_AcquireMemory(hmem, &mem_buffer, &size_in_bytes);

    // save the buffer in a file stream
    FILE *stream = fopen("buffer.png", "wb");
    if(stream) {
        fwrite(mem_buffer, sizeof(BYTE), size_in_bytes, stream);
        fclose(stream);
    }

    // close and free the memory stream
    FreeImage_CloseMemory(hmem);

}
Пример #7
0
/**
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) {
	BOOL mEnd = FALSE;
	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;
			}

			memcpy(&mLength, &data[chunk_pos], 4);
			mng_SwapLong(&mLength);
			chunk_pos += 4;

			const DWORD next_chunk_pos = chunk_pos + 4 + mLength + 4;
			if(next_chunk_pos > size_in_bytes) {
				break;
			}

			// get chunk name
			if(memcmp(&data[chunk_pos], chunk_name, 4) == 0) {
				chunk_pos -= 4;	// found chunk
				*start_pos = chunk_pos;
				*next_pos = next_chunk_pos;
				return TRUE;
			}
			
			chunk_pos = next_chunk_pos;
		}

		return FALSE;

	} catch(int) {
		return FALSE;
	}
}
Пример #8
0
void DLL_CALLCONV
FreeImage_UnlockPage(FIMULTIBITMAP *bitmap, FIBITMAP *page, BOOL changed) {
	if ((bitmap) && (page)) {
		MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);

		// find out if the page we try to unlock is actually locked...

		if (header->locked_pages.find(page) != header->locked_pages.end()) {
			// store the bitmap compressed in the cache for later writing
			
			if (changed && !header->read_only) {
				header->changed = TRUE;

				// cut loose the block from the rest

				BlockListIterator i = FreeImage_FindBlock(bitmap, header->locked_pages[page]);

				// compress the data

				DWORD compressed_size = 0;
				BYTE *compressed_data = NULL;

				// open a memory handle
				FIMEMORY *hmem = FreeImage_OpenMemory();
				// save the page to memory
				FreeImage_SaveToMemory(header->cache_fif, page, hmem, 0);
				// get the buffer from the memory stream
				FreeImage_AcquireMemory(hmem, &compressed_data, &compressed_size);

				// write the data to the cache
				
				if (i->m_type == BLOCK_REFERENCE) {
					header->m_cachefile.deleteFile(i->getReference());
				}
				
				int iPage = header->m_cachefile.writeFile(compressed_data, compressed_size);
				
				*i = PageBlock(BLOCK_REFERENCE, iPage, compressed_size);
				
				// get rid of the compressed data

				FreeImage_CloseMemory(hmem);
			}

			// reset the locked page so that another page can be locked

			FreeImage_Unload(page);

			header->locked_pages.erase(page);
		}
	}
}
Пример #9
0
FIMEMORY* FreeImage_SaveToMem(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, fiio_mem_handle *handle, int flags)
{
	if (handle) {
		FIMEMORY *hmem = FreeImage_OpenMemory(NULL, 0);
		if(fif == FIF_UNKNOWN)
			fif = FIF_BMP;
		handle->curpos = 0;
		FreeImage_SaveToMemory(fif, dib, hmem, flags);
		FreeImage_AcquireMemory(hmem, (BYTE **)&handle->data, (DWORD *)&handle->datalen);
		return hmem;
	}
	return NULL;
}
Пример #10
0
void DLL_CALLCONV
FreeImage_InsertPage(FIMULTIBITMAP *bitmap, int page, FIBITMAP *data) {
	if ((bitmap) && (data)) {
		if (page < FreeImage_GetPageCount(bitmap)) {
			MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);

			if ((!header->read_only) && (header->locked_pages.empty())) {
				DWORD compressed_size = 0;
				BYTE *compressed_data = NULL;

				// compress the bitmap data

				// open a memory handle
				FIMEMORY *hmem = FreeImage_OpenMemory();
				// save the file to memory
				FreeImage_SaveToMemory(header->cache_fif, data, hmem, 0);
				// get the buffer from the memory stream
				FreeImage_AcquireMemory(hmem, &compressed_data, &compressed_size);

				// write the compressed data to the cache

				int ref = header->m_cachefile->writeFile(compressed_data, compressed_size);

				// add a block

				if (page > 0) {
					BlockListIterator block_source = FreeImage_FindBlock(bitmap, page);

					BlockReference *block = new BlockReference(ref, compressed_size);

					header->m_blocks.insert(block_source, (BlockTypeS *)block);
				} else {
					BlockReference *block = new BlockReference(ref, compressed_size);

					header->m_blocks.push_front((BlockTypeS *)block);
				}

				// get rid of the compressed buffer

				FreeImage_CloseMemory(hmem);

				header->changed = TRUE;
				header->page_count = -1;
			}
		}
	}
}
Пример #11
0
/**
Write a metadata model as a TIF IFD, returns the IFD as a buffer.
The buffer is allocated by the function and must be freed by the caller, using 'free'.
@param dib Input FIBITMAP
@param md_model Metadata model to write
@param ppbProfile Returned buffer
@param uProfileLength Returned buffer size
@return Returns TRUE if successful, FALSE otherwise
@see tiff_write_ifd
*/
BOOL
tiff_get_ifd_profile(FIBITMAP *dib, FREE_IMAGE_MDMODEL md_model, BYTE **ppbProfile, unsigned *uProfileLength) {
	FIMEMORY *hmem = NULL;

	try {
		// open a memory stream
		hmem = FreeImage_OpenMemory(NULL, 0);
		if(!hmem) {
			throw(1);
		}

		// write the metadata model as a TIF IFD
		BOOL bResult = tiff_write_ifd(dib, md_model, hmem);

		if(bResult) {
			BYTE *data = NULL;
			DWORD size_in_bytes = 0;

			// get a pointer to the stream buffer
			FreeImage_AcquireMemory(hmem, &data, &size_in_bytes);
			
			// (re-)allocate output buffer
			BYTE *pbProfile = *ppbProfile;
			pbProfile = (BYTE*)realloc(pbProfile, size_in_bytes);
			if(!pbProfile) {
				throw(1);
			} else {
				// copy IFD
				memcpy(pbProfile, data, size_in_bytes);
				*ppbProfile = pbProfile;
				*uProfileLength = size_in_bytes;
			}
		}

		// free the memory stream
		FreeImage_CloseMemory(hmem);

		return bResult;

	} catch(int) {
		FreeImage_CloseMemory(hmem);
		return FALSE;
	}
}
Пример #12
0
/**
   Insert a chunk just before the inNextChunkName chunk
   @param hPngMemory PNG stream handle
   @param start_pos Start position of the inNextChunkName chunk
   @param next_pos Start position of the next chunk
   @return Returns TRUE if successfull, returns FALSE otherwise
*/
static BOOL
mng_CopyInsertChunks(FIMEMORY *hPngMemory, BYTE *inNextChunkName, BYTE *inInsertChunk, DWORD inChunkLength, DWORD start_pos, DWORD next_pos) {
    BYTE *data = NULL;
    DWORD size_in_bytes = 0;

    // length of the chunk to check
    DWORD chunk_length = next_pos - start_pos;
    if(chunk_length == 0) {
        return TRUE;
    }

    // get a pointer to the stream buffer
    FreeImage_AcquireMemory(hPngMemory, &data, &size_in_bytes);
    if(!(data && size_in_bytes) || (size_in_bytes < 20) || (chunk_length >= size_in_bytes)) {
        // not enough space to read a signature(8 bytes) + a chunk(at least 12 bytes)
        return FALSE;
    }

    // new file length
    unsigned buffer_size = inChunkLength + size_in_bytes;

    BYTE *buffer = (BYTE*)malloc(buffer_size * sizeof(BYTE));
    if(!buffer) {
        return FALSE;
    }
    unsigned p = 0;
    memcpy(&buffer[p], &data[0], start_pos);
    p += start_pos;
    memcpy(&buffer[p], inInsertChunk, inChunkLength);
    p += inChunkLength;
    memcpy(&buffer[p], &data[start_pos], size_in_bytes - start_pos);

    // seek to the start of the stream
    FreeImage_SeekMemory(hPngMemory, 0, SEEK_SET);
    // re-write the stream
    FreeImage_WriteMemory(buffer, 1, buffer_size, hPngMemory);

    free(buffer);

    return TRUE;
}
Пример #13
0
static PageBlock
FreeImage_SavePageToBlock(MULTIBITMAPHEADER *header, FIBITMAP *data) {
	PageBlock res;
	
	if (header->read_only || !header->locked_pages.empty()) {
		return res;
	}

	DWORD compressed_size = 0;
	BYTE *compressed_data = NULL;

	// compress the bitmap data

	// open a memory handle
	FIMEMORY *hmem = FreeImage_OpenMemory();
	if(hmem==NULL) {
		return res;
	}
	// save the file to memory
	if(!FreeImage_SaveToMemory(header->cache_fif, data, hmem, 0)) {
		FreeImage_CloseMemory(hmem);
		return res;
	}
	// get the buffer from the memory stream
	if(!FreeImage_AcquireMemory(hmem, &compressed_data, &compressed_size)) {
		FreeImage_CloseMemory(hmem);
		return res;
	}
	
	// write the compressed data to the cache
	int ref = header->m_cachefile.writeFile(compressed_data, compressed_size);
	// get rid of the compressed data
	FreeImage_CloseMemory(hmem);
	
	res = PageBlock(BLOCK_REFERENCE, ref, compressed_size);
	
	return res;
}
Пример #14
0
void DLL_CALLCONV
FreeImage_AppendPage(FIMULTIBITMAP *bitmap, FIBITMAP *data) {
	if ((bitmap) && (data)) {
		MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap);

		if ((!header->read_only) && (header->locked_pages.empty())) {
			DWORD compressed_size = 0;
			BYTE *compressed_data = NULL;

			// compress the bitmap data

			// open a memory handle
			FIMEMORY *hmem = FreeImage_OpenMemory();
			// save the file to memory
			FreeImage_SaveToMemory(header->cache_fif, data, hmem, 0);
			// get the buffer from the memory stream
			FreeImage_AcquireMemory(hmem, &compressed_data, &compressed_size);

			// write the compressed data to the cache

			int ref = header->m_cachefile->writeFile(compressed_data, compressed_size);

			BlockReference *block = new BlockReference(ref, compressed_size);

			// get rid of the compressed data

			FreeImage_CloseMemory(hmem);

			// add the block

			header->m_blocks.push_back((BlockTypeS *)block);
			header->changed = TRUE;
			header->page_count = -1;
		}
	}
}
Пример #15
0
/**
   Write a FIBITMAP to a JNG stream
   @param format_id ID of the caller
   @param io Stream i/o functions
   @param dib Image to be saved
   @param handle Stream handle
   @param flags Saving flags
   @return Returns TRUE if successful, returns FALSE otherwise
*/
BOOL
mng_WriteJNG(int format_id, FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int flags) {
    DWORD jng_width = 0;
    DWORD jng_height = 0;
    BYTE jng_color_type = 0;
    BYTE jng_image_sample_depth = 8;
    BYTE jng_image_compression_method = 8;  //  8: ISO-10918-1 Huffman-coded baseline JPEG.
    BYTE jng_image_interlace_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;

    BYTE buffer[16];

    FIMEMORY *hJngMemory = NULL;
    FIMEMORY *hJpegMemory = NULL;
    FIMEMORY *hPngMemory = NULL;

    FIBITMAP *dib_rgb = NULL;
    FIBITMAP *dib_alpha = NULL;

    if(!dib || (FreeImage_GetImageType(dib) != FIT_BITMAP)) {
        return FALSE;
    }

    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);
        }
        return FALSE;
    }
}
Пример #16
0
BOOL fipMemoryIO::acquire(BYTE **data, DWORD *size_in_bytes) {
	return FreeImage_AcquireMemory(_hmem, data, size_in_bytes);
}
Пример #17
0
    GXBOOL RenderTargetImpl::SaveToMemory(clstd::MemBuffer* pBuffer, GXLPCSTR pImageFormat)
    {
      GXSIZE sDimension;
      GXBOOL bval = TRUE;
      GXFormat format = m_pColorTexture->GetFormat();
      m_pColorTexture->GetDimension(&sDimension);
      Texture* pReadBackTexture = NULL;

      GetColorTexture(&pReadBackTexture, GXResUsage::Read);

      Texture::MAPPED mapped;
      if(pReadBackTexture->Map(&mapped, GXResMap::Read))
      {
        GXUINT bpp = GetBytesOfGraphicsFormat(format);

        GXLPVOID pSourceBits = mapped.pBits;
        GXINT nSourcePitch = mapped.Pitch;
        clstd::Image temp_image;
        FREE_IMAGE_TYPE fit = FIT_BITMAP;
        switch(format)
        {
        case Format_R8G8B8A8:
          temp_image.Set(sDimension.cx, sDimension.cy, "RGBA", 8, pSourceBits, nSourcePitch);
          break;
        case Format_B8G8R8X8:
          temp_image.Set(sDimension.cx, sDimension.cy, "BGRX", 8, pSourceBits, nSourcePitch);
          break;
        case Format_B8G8R8:
          temp_image.Set(sDimension.cx, sDimension.cy, "BGRX", 8, pSourceBits, nSourcePitch);
          break;
        case Format_R8:
          temp_image.Set(sDimension.cx, sDimension.cy, "R", 8, pSourceBits, nSourcePitch);
          break;
        case Format_R8G8:
          temp_image.Set(sDimension.cx, sDimension.cy, "RG", 8, pSourceBits, nSourcePitch);
          break;
        case Format_R32G32B32A32_Float:
          fit = FIT_RGBAF;
          break;
        case Format_R32:
          fit = FIT_FLOAT;
          break;
        }

        if(temp_image.GetDataSize() > 0)
        {
          temp_image.SetFormat("BGRA");
          pSourceBits = temp_image.GetLine(0);
          nSourcePitch = temp_image.GetPitch();
          bpp = temp_image.GetChannels();
        }

        FIBITMAP* fibmp = (fit == FIT_BITMAP)
          ? FreeImage_Allocate(sDimension.cx, sDimension.cy, bpp * 8)
          : FreeImage_AllocateT(fit, sDimension.cx, sDimension.cy, bpp * 8);
        BYTE* pDest = FreeImage_GetBits(fibmp);
        GXINT nDestPitch = FreeImage_GetPitch(fibmp);

        pDest += nDestPitch * (sDimension.cy - 1);
        for(int y = 0; y < sDimension.cy; y++)
        {
          memcpy(pDest, pSourceBits, clMin(nDestPitch, nSourcePitch));

          pDest -= nDestPitch;
          pSourceBits = reinterpret_cast<GXLPVOID>(reinterpret_cast<size_t>(pSourceBits) + nSourcePitch);
        }

        pReadBackTexture->Unmap();

        FREE_IMAGE_FORMAT fi_format = FIF_UNKNOWN;
        clStringA strFormat = pImageFormat;
        strFormat.MakeUpper();

        if(strFormat == "PNG") {
          fi_format = FIF_PNG;
        }
        else if(strFormat == "JPEG" || strFormat == "JPG") {
          fi_format = FIF_JPEG;
        }
        else if(strFormat == "TIF" || strFormat == "TIFF") {
          fi_format = FIF_TIFF;
        }
        else if(strFormat == "TGA") {
          fi_format = FIF_TARGA;
        }
        else if(strFormat == "BMP") {
          fi_format = FIF_BMP;
        }
        else if(strFormat == "EXR") {
          fi_format = FIF_EXR;
        }

        if(fi_format != FIF_UNKNOWN)
        {
          FIMEMORY* fimemory = FreeImage_OpenMemory();
          if(FreeImage_SaveToMemory(fi_format, fibmp, fimemory))
          {
            BYTE *pData;
            DWORD size_in_bytes;
            if(FreeImage_AcquireMemory(fimemory, &pData, &size_in_bytes))
            {
              pBuffer->Resize(0, FALSE);
              pBuffer->Append(pData, size_in_bytes);
            }
            else
            {
              bval = FALSE;
            }
          }
          else
          {
            bval = FALSE;
          }
          FreeImage_CloseMemory(fimemory);
        }
        else
        {
          bval = FALSE;
        }

        FreeImage_Unload(fibmp);
      }

      SAFE_RELEASE(pReadBackTexture);
      return bval;
    }
Пример #18
0
static void saveImage(ofPixels_<PixelType> & pix, ofBuffer & buffer, ofImageFormat format, ofImageQualityType qualityLevel) {
	//thanks to alvaro casinelli for the implementation

	ofInitFreeImage();

	if (pix.isAllocated() == false){
		ofLog(OF_LOG_ERROR,"error saving image - pixels aren't allocated");
		return;
	}

	#ifdef TARGET_LITTLE_ENDIAN
	if(sizeof(PixelType) == 1) {
		pix.swapRgb();
	}
	#endif

	FIBITMAP * bmp	= getBmpFromPixels(pix);

	#ifdef TARGET_LITTLE_ENDIAN
	if(sizeof(PixelType) == 1) {
		pix.swapRgb();
	}
	#endif

	if (bmp)  // bitmap successfully created
	{
		   // (b) open a memory stream to compress the image onto mem_buffer:
		   //
		   FIMEMORY *hmem = FreeImage_OpenMemory();
		   // (c) encode and save the image to the memory (on dib FIBITMAP image):
		   //
		   if(FREE_IMAGE_FORMAT(format) == FIF_JPEG) {
				int quality = JPEG_QUALITYSUPERB;
				switch(qualityLevel) {
					case OF_IMAGE_QUALITY_WORST: quality = JPEG_QUALITYBAD; break;
					case OF_IMAGE_QUALITY_LOW: quality = JPEG_QUALITYAVERAGE; break;
					case OF_IMAGE_QUALITY_MEDIUM: quality = JPEG_QUALITYNORMAL; break;
					case OF_IMAGE_QUALITY_HIGH: quality = JPEG_QUALITYGOOD; break;
					case OF_IMAGE_QUALITY_BEST: quality = JPEG_QUALITYSUPERB; break;
				}
				FreeImage_SaveToMemory(FIF_JPEG, bmp, hmem, quality);
		   }else{
				FreeImage_SaveToMemory((FREE_IMAGE_FORMAT)format, bmp, hmem);
		   }
		   /*

		  NOTE: at this point, hmem contains the entire data in memory stored in fif format. the
		  amount of space used by the memory is equal to file_size:
		  long file_size = FreeImage_TellMemory(hmem);
		  but can also be retrieved by FreeImage_AcquireMemory that retrieves both the
		  length of the buffer, and the buffer memory address.
		  */
			#ifdef TARGET_WIN32
		   	   DWORD size_in_bytes = 0;
			#else
		   	   uint32_t size_in_bytes = 0;
			#endif
		   // Save compressed data on mem_buffer
		   // note: FreeImage_AquireMemory allocates space for aux_mem_buffer):
		   //
		   unsigned char *mem_buffer = NULL;
		   if (!FreeImage_AcquireMemory(hmem, &mem_buffer, &size_in_bytes))
				   cout << "Error aquiring compressed image from memory" << endl;

		   /*
			  Now, before closing the memory stream, copy the content of mem_buffer
			  to an auxiliary buffer
		    */

		   buffer.set((char*)mem_buffer,size_in_bytes);

		   // Finally, close the FIBITMAP object, or we will get a memory leak:
		   FreeImage_Unload(bmp);

		   // Close the memory stream (otherwise we may get a memory leak).
		   FreeImage_CloseMemory(hmem);
	}
}
Пример #19
0
static bool saveImage(const ofPixels_<PixelType> & _pix, ofBuffer & buffer, ofImageFormat format, ofImageQualityType qualityLevel) {
	// thanks to alvaro casinelli for the implementation

	ofInitFreeImage();

	if (_pix.isAllocated() == false){
		ofLogError("ofImage","saveImage(): couldn't save to ofBuffer, pixels are not allocated");
		return false;
	}

	if(format==OF_IMAGE_FORMAT_JPEG && (_pix.getNumChannels()==4 || _pix.getBitsPerChannel() > 8)){
		ofPixels pix3 = _pix;
		pix3.setNumChannels(3);
		return saveImage(pix3,buffer,format,qualityLevel);
	}


	FIBITMAP * bmp = nullptr;
	#ifdef TARGET_LITTLE_ENDIAN
	if(sizeof(PixelType) == 1 && (_pix.getPixelFormat()==OF_PIXELS_RGB || _pix.getPixelFormat()==OF_PIXELS_RGBA)) {	// Make a local copy.
		ofPixels_<PixelType> pix = _pix;
		pix.swapRgb();
		bmp	= getBmpFromPixels(pix);
	}else{
	#endif

		bmp	= getBmpFromPixels(_pix);


	#ifdef TARGET_LITTLE_ENDIAN
	}
	#endif

	if (bmp)  // bitmap successfully created
	{
		bool returnValue;
		// (b) open a memory stream to compress the image onto mem_buffer:
		//
		FIMEMORY *hmem = FreeImage_OpenMemory();
		// (c) encode and save the image to the memory (on dib FIBITMAP image):
		//
		if(FREE_IMAGE_FORMAT(format) == FIF_JPEG) {
			int quality = JPEG_QUALITYSUPERB;
			switch(qualityLevel) {
				case OF_IMAGE_QUALITY_WORST: quality = JPEG_QUALITYBAD; break;
				case OF_IMAGE_QUALITY_LOW: quality = JPEG_QUALITYAVERAGE; break;
				case OF_IMAGE_QUALITY_MEDIUM: quality = JPEG_QUALITYNORMAL; break;
				case OF_IMAGE_QUALITY_HIGH: quality = JPEG_QUALITYGOOD; break;
				case OF_IMAGE_QUALITY_BEST: quality = JPEG_QUALITYSUPERB; break;
			}
			returnValue = FreeImage_SaveToMemory(FIF_JPEG, bmp, hmem, quality);
		}else{
			returnValue = FreeImage_SaveToMemory((FREE_IMAGE_FORMAT)format, bmp, hmem);
		}

		/*

		NOTE: at this point, hmem contains the entire data in memory stored in fif format. the
		amount of space used by the memory is equal to file_size:
		long file_size = FreeImage_TellMemory(hmem);
		but can also be retrieved by FreeImage_AcquireMemory that retrieves both the
		length of the buffer, and the buffer memory address.
		*/
		#ifdef TARGET_WIN32
		   DWORD size_in_bytes = 0;
		#else
		   std::uint32_t size_in_bytes = 0;
		#endif
		// Save compressed data on mem_buffer
		// note: FreeImage_AquireMemory allocates space for aux_mem_buffer):
		//
		unsigned char *mem_buffer = nullptr;
		if (!FreeImage_AcquireMemory(hmem, &mem_buffer, &size_in_bytes)){
			ofLogError("ofImage") << "saveImage(): couldn't save to ofBuffer, aquiring compressed image from memory failed";
			return false;
		}

		/*
		  Now, before closing the memory stream, copy the content of mem_buffer
		  to an auxiliary buffer
		*/

		buffer.set((char*)mem_buffer,size_in_bytes);

		// Finally, close the FIBITMAP object, or we will get a memory leak:
		FreeImage_Unload(bmp);

		// Close the memory stream (otherwise we may get a memory leak).
		FreeImage_CloseMemory(hmem);
		return returnValue;
	}else{
		return false;
	}
}
Пример #20
0
static BOOL DLL_CALLCONV
Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
	WebPMux *mux = NULL;
	FIMEMORY *hmem = NULL;
	WebPData webp_image;
	WebPData output_data = { 0 };
	WebPMuxError error_status;

	int copy_data = 1;	// 1 : copy data into the mux, 0 : keep a link to local data

	if(!dib || !handle || !data) {
		return FALSE;
	}

	try {

		// get the MUX object
		mux = (WebPMux*)data;
		if(!mux) {
			return FALSE;
		}

		// --- prepare image data ---

		// encode image as a WebP blob
		hmem = FreeImage_OpenMemory();
		if(!hmem || !EncodeImage(hmem, dib, flags)) {
			throw (1);
		}
		// store the blob into the mux
		BYTE *data = NULL;
		DWORD data_size = 0;
		FreeImage_AcquireMemory(hmem, &data, &data_size);
		webp_image.bytes = data;
		webp_image.size = data_size;
		error_status = WebPMuxSetImage(mux, &webp_image, copy_data);
		// no longer needed since copy_data == 1
		FreeImage_CloseMemory(hmem);
		hmem = NULL;
		if(error_status != WEBP_MUX_OK) {
			throw (1);
		}

		// --- set metadata ---
		
		// set ICC color profile
		{
			FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(dib);
			if (iccProfile->size && iccProfile->data) {
				WebPData icc_profile;
				icc_profile.bytes = (uint8_t*)iccProfile->data;
				icc_profile.size = (size_t)iccProfile->size;
				error_status = WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data);
				if(error_status != WEBP_MUX_OK) {
					throw (1);
				}
			}
		}

		// set XMP metadata
		{
			FITAG *tag = NULL;
			if(FreeImage_GetMetadata(FIMD_XMP, dib, g_TagLib_XMPFieldName, &tag)) {
				WebPData xmp_profile;
				xmp_profile.bytes = (uint8_t*)FreeImage_GetTagValue(tag);
				xmp_profile.size = (size_t)FreeImage_GetTagLength(tag);
				error_status = WebPMuxSetChunk(mux, "XMP ", &xmp_profile, copy_data);
				if(error_status != WEBP_MUX_OK) {
					throw (1);
				}
			}
		}

		// set Exif metadata
		{
			FITAG *tag = NULL;
			if(FreeImage_GetMetadata(FIMD_EXIF_RAW, dib, g_TagLib_ExifRawFieldName, &tag)) {
				WebPData exif_profile;
				exif_profile.bytes = (uint8_t*)FreeImage_GetTagValue(tag);
				exif_profile.size = (size_t)FreeImage_GetTagLength(tag);
				error_status = WebPMuxSetChunk(mux, "EXIF", &exif_profile, copy_data);
				if(error_status != WEBP_MUX_OK) {
					throw (1);
				}
			}
		}
		
		// get data from mux in WebP RIFF format
		error_status = WebPMuxAssemble(mux, &output_data);
		if(error_status != WEBP_MUX_OK) {
			FreeImage_OutputMessageProc(s_format_id, "Failed to create webp output file");
			throw (1);
		}

		// write the file to the output stream
		if(io->write_proc((void*)output_data.bytes, 1, (unsigned)output_data.size, handle) != output_data.size) {
			FreeImage_OutputMessageProc(s_format_id, "Failed to write webp output file");
			throw (1);
		}

		// free WebP output file
		WebPDataClear(&output_data);

		return TRUE;

	} catch(int) {
		if(hmem) {
			FreeImage_CloseMemory(hmem);
		}
		
		WebPDataClear(&output_data);

		return FALSE;
	}
}
Пример #21
0
/**
   Load a FIBITMAP from a MNG or a JNG stream
   @param format_id ID of the caller
   @param io Stream i/o functions
   @param handle Stream handle
   @param Offset Start of the first chunk
   @param flags Loading flags
   @return Returns a dib if successful, returns NULL otherwise
*/
FIBITMAP*
mng_ReadChunks(int format_id, FreeImageIO *io, fi_handle handle, long Offset, int flags = 0) {
    DWORD mLength = 0;
    BYTE mChunkName[5];
    BYTE *mChunk = NULL;
    DWORD crc_file;
    long LastOffset;
    long mOrigPos;
    BYTE *PLTE_file_chunk = NULL;   // whole PLTE chunk (lentgh, name, array, crc)
    DWORD PLTE_file_size = 0;       // size of PLTE chunk

    BOOL m_HasGlobalPalette = FALSE; // may turn to TRUE in PLTE chunk
    unsigned m_TotalBytesOfChunks = 0;
    FIBITMAP *dib = NULL;
    FIBITMAP *dib_alpha = NULL;

    FIMEMORY *hJpegMemory = NULL;
    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;

                case gAMA:
                    break;

                case pHYs:
                    // unit is pixels per meter
                    memcpy(&res_x, &mChunk[0], 4);
                    mng_SwapLong(&res_x);
                    memcpy(&res_y, &mChunk[4], 4);
                    mng_SwapLong(&res_y);
                    break;

                case bKGD:
                    memcpy(&bk_red, &mChunk[0], 2);
                    mng_SwapShort(&bk_red);
                    rgbBkColor.rgbRed = (BYTE)bk_red;
                    memcpy(&bk_green, &mChunk[2], 2);
                    mng_SwapShort(&bk_green);
                    rgbBkColor.rgbGreen = (BYTE)bk_green;
                    memcpy(&bk_blue, &mChunk[4], 2);
                    mng_SwapShort(&bk_blue);
                    rgbBkColor.rgbBlue = (BYTE)bk_blue;
                    hasBkColor = TRUE;
                    break;

                case tEXt:
                    mng_SetMetadata_tEXt(key_value_pair, mChunk, mLength);
                    break;

                case UNKNOWN_CHUNCK:
                default:
                    break;


            } // switch( GetChunckType )
        } // while(!mEnd)

        FreeImage_CloseMemory(hJpegMemory);
        FreeImage_CloseMemory(hPngMemory);
        FreeImage_CloseMemory(hIDATMemory);
        free(mChunk);
        free(PLTE_file_chunk);

        // convert to 32-bit if a transparent layer is available
        if(!header_only && dib_alpha) {
            FIBITMAP *dst = FreeImage_ConvertTo32Bits(dib);
            if((FreeImage_GetBPP(dib_alpha) == 8) && (FreeImage_GetImageType(dib_alpha) == FIT_BITMAP)) {
                FreeImage_SetChannel(dst, dib_alpha, FICC_ALPHA);
            } else {
                FIBITMAP *dst_alpha = FreeImage_ConvertTo8Bits(dib_alpha);
                FreeImage_SetChannel(dst, dst_alpha, FICC_ALPHA);
                FreeImage_Unload(dst_alpha);
            }
            FreeImage_Unload(dib);
            dib = dst;
        }
        FreeImage_Unload(dib_alpha);

        if(dib) {
            // set metadata
            FreeImage_SetDotsPerMeterX(dib, res_x);
            FreeImage_SetDotsPerMeterY(dib, res_y);
            if(hasBkColor) {
                FreeImage_SetBackgroundColor(dib, &rgbBkColor);
            }
            if(key_value_pair.size()) {
                for(tEXtMAP::iterator j = key_value_pair.begin(); j != key_value_pair.end(); j++) {
                    std::string key = (*j).first;
                    std::string value = (*j).second;
                    mng_SetKeyValue(FIMD_COMMENTS, dib, key.c_str(), value.c_str());
                }
            }
        }

        return dib;

    } catch(const char *text) {
        FreeImage_CloseMemory(hJpegMemory);
        FreeImage_CloseMemory(hPngMemory);
        FreeImage_CloseMemory(hIDATMemory);
        free(mChunk);
        free(PLTE_file_chunk);
        FreeImage_Unload(dib);
        FreeImage_Unload(dib_alpha);
        if(text) {
            FreeImage_OutputMessageProc(format_id, text);
        }
        return NULL;
    }
}