static BOOL openStdIO(const char* src_file, const char* dst_file, FreeImageIO* dst_io, fi_handle* src_handle, fi_handle* dst_handle) { *src_handle = NULL; *dst_handle = NULL; FreeImageIO io; SetDefaultIO (&io); const BOOL isSameFile = (dst_file && (strcmp(src_file, dst_file) == 0)) ? TRUE : FALSE; FILE* srcp = NULL; FILE* dstp = NULL; if(isSameFile) { srcp = fopen(src_file, "r+b"); dstp = srcp; } else { srcp = fopen(src_file, "rb"); if(dst_file) { dstp = fopen(dst_file, "wb"); } } if(!srcp || (dst_file && !dstp)) { if(!srcp) { FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open \"%s\" for reading", src_file); } else { FreeImage_OutputMessageProc(FIF_JPEG, "Cannot open \"%s\" for writing", dst_file); } closeStdIO(srcp, dstp); return FALSE; } if(FreeImage_GetFileTypeFromHandle(&io, srcp) != FIF_JPEG) { FreeImage_OutputMessageProc(FIF_JPEG, " Source file \"%s\" is not jpeg", src_file); closeStdIO(srcp, dstp); return FALSE; } *dst_io = io; *src_handle = srcp; *dst_handle = dstp; return TRUE; }
ls_jpeg_output_message (j_common_ptr cinfo) { char buffer[JMSG_LENGTH_MAX]; // create the message (*cinfo->err->format_message)(cinfo, buffer); // send it to user's message proc FreeImage_OutputMessageProc(FIF_JPEG, buffer); }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { if (handle != NULL) { BITMAPFILEHEADER bitmapfileheader; DWORD type = 0; BYTE magic[2]; // we use this offset value to make seemingly absolute seeks relative in the file long offset_in_file = io->tell_proc(handle); // read the magic io->read_proc(&magic, sizeof(magic), 1, handle); // compare the magic with the number we know // somebody put a comment here explaining the purpose of this loop while (memcmp(&magic, "BA", 2) == 0) { io->read_proc(&bitmapfileheader.bfSize, sizeof(DWORD), 1, handle); io->read_proc(&bitmapfileheader.bfReserved1, sizeof(WORD), 1, handle); io->read_proc(&bitmapfileheader.bfReserved2, sizeof(WORD), 1, handle); io->read_proc(&bitmapfileheader.bfOffBits, sizeof(DWORD), 1, handle); io->read_proc(&magic, sizeof(magic), 1, handle); } // read the fileheader io->seek_proc(handle, 0 - sizeof(magic), SEEK_CUR); io->read_proc(&bitmapfileheader, sizeof(BITMAPFILEHEADER), 1, handle); #ifdef FREEIMAGE_BIGENDIAN SwapFileHeader(&bitmapfileheader); #endif // read the first byte of the infoheader io->read_proc(&type, sizeof(DWORD), 1, handle); io->seek_proc(handle, 0 - sizeof(DWORD), SEEK_CUR); #ifdef FREEIMAGE_BIGENDIAN SwapLong(&type); #endif // call the appropriate load function for the found bitmap type if (type == 40) return LoadWindowsBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits); if (type == 12) return LoadOS21XBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits); if (type <= 64) return LoadOS22XBMP(io, handle, flags, offset_in_file + bitmapfileheader.bfOffBits); FreeImage_OutputMessageProc(s_format_id, "unknown bmp subtype with id %d", type); } return NULL; }
/** Save using EXR_LC compression (works only with RGB[A]F images) */ static BOOL SaveAsEXR_LC(C_OStream& ostream, FIBITMAP *dib, Imf::Header& header, int width, int height) { int x, y; Imf::RgbaChannels rgbaChannels; try { FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); // convert from float to half Imf::Array2D<Imf::Rgba> pixels(height, width); switch(image_type) { case FIT_RGBF: rgbaChannels = Imf::WRITE_YC; for(y = 0; y < height; y++) { FIRGBF *src_bits = (FIRGBF*)FreeImage_GetScanLine(dib, height - 1 - y); for(x = 0; x < width; x++) { Imf::Rgba &dst_bits = pixels[y][x]; dst_bits.r = src_bits[x].red; dst_bits.g = src_bits[x].green; dst_bits.b = src_bits[x].blue; } } break; case FIT_RGBAF: rgbaChannels = Imf::WRITE_YCA; for(y = 0; y < height; y++) { FIRGBAF *src_bits = (FIRGBAF*)FreeImage_GetScanLine(dib, height - 1 - y); for(x = 0; x < width; x++) { Imf::Rgba &dst_bits = pixels[y][x]; dst_bits.r = src_bits[x].red; dst_bits.g = src_bits[x].green; dst_bits.b = src_bits[x].blue; dst_bits.a = src_bits[x].alpha; } } break; default: THROW (Iex::IoExc, "Bad image type"); break; } // write the data Imf::RgbaOutputFile file(ostream, header, rgbaChannels); file.setFrameBuffer (&pixels[0][0], 1, width); file.writePixels (height); return TRUE; } catch(Iex::BaseExc & e) { FreeImage_OutputMessageProc(s_format_id, e.what()); return FALSE; } }
/** Default error routine. change this to change error handling */ static BOOL rgbe_Error(rgbe_error_code error_code, const char *msg) { switch (error_code) { case rgbe_read_error: FreeImage_OutputMessageProc(s_format_id, "RGBE read error"); break; case rgbe_write_error: FreeImage_OutputMessageProc(s_format_id, "RGBE write error"); break; case rgbe_format_error: FreeImage_OutputMessageProc(s_format_id, "RGBE bad file format: %s\n", msg); break; default: case rgbe_memory_error: FreeImage_OutputMessageProc(s_format_id, "RGBE error: %s\n",msg); } return FALSE; }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { FIBITMAP *dib = NULL; if(!handle) { return NULL; } BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; try { rgbeHeaderInfo header_info; unsigned width, height; // Read the header if(rgbe_ReadHeader(io, handle, &width, &height, &header_info) == FALSE) { return NULL; } // allocate a RGBF image dib = FreeImage_AllocateHeaderT(header_only, FIT_RGBF, width, height); if(!dib) { throw FI_MSG_ERROR_MEMORY; } // set the metadata as comments rgbe_ReadMetadata(dib, &header_info); if(header_only) { // header only mode return dib; } // read the image pixels and fill the dib for(unsigned y = 0; y < height; y++) { FIRGBF *scanline = (FIRGBF*)FreeImage_GetScanLine(dib, height - 1 - y); if(!rgbe_ReadPixels_RLE(io, handle, scanline, width, 1)) { FreeImage_Unload(dib); return NULL; } } } catch(const char *text) { if(dib != NULL) { FreeImage_Unload(dib); } FreeImage_OutputMessageProc(s_format_id, text); } return dib; }
/** Get the embedded JPEG preview image from RAW picture with included Exif Data. @param RawProcessor Libraw handle @param flags JPEG load flags @return Returns the loaded dib if successfull, returns NULL otherwise */ static FIBITMAP * libraw_LoadEmbeddedPreview(LibRaw *RawProcessor, int flags) { FIBITMAP *dib = NULL; libraw_processed_image_t *thumb_image = NULL; try { // unpack data if(RawProcessor->unpack_thumb() != LIBRAW_SUCCESS) { // run silently "LibRaw : failed to run unpack_thumb" return NULL; } // retrieve thumb image int error_code = 0; thumb_image = RawProcessor->dcraw_make_mem_thumb(&error_code); if(thumb_image) { if(thumb_image->type != LIBRAW_IMAGE_BITMAP) { // attach the binary data to a memory stream FIMEMORY *hmem = FreeImage_OpenMemory((BYTE*)thumb_image->data, (DWORD)thumb_image->data_size); // get the file type FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeFromMemory(hmem, 0); if(fif == FIF_JPEG) { // rotate according to Exif orientation flags |= JPEG_EXIFROTATE; } // load an image from the memory stream dib = FreeImage_LoadFromMemory(fif, hmem, flags); // close the stream FreeImage_CloseMemory(hmem); } else if((flags & FIF_LOAD_NOPIXELS) != FIF_LOAD_NOPIXELS) { // convert processed data to output dib dib = libraw_ConvertProcessedImageToDib(thumb_image); } } else { throw "LibRaw : failed to run dcraw_make_mem_thumb"; } // clean-up and return RawProcessor->dcraw_clear_mem(thumb_image); return dib; } catch(const char *text) { // clean-up and return if(thumb_image) { RawProcessor->dcraw_clear_mem(thumb_image); } if(text != NULL) { FreeImage_OutputMessageProc(s_format_id, text); } } return NULL; }
FITAG * DLL_CALLCONV FreeImage_CloneTag(FITAG *tag) { if(!tag) return NULL; // allocate a new tag FITAG *clone = FreeImage_CreateTag(); if(!clone) return NULL; try { // copy the tag FITAGHEADER *src_tag = (FITAGHEADER *)tag->data; FITAGHEADER *dst_tag = (FITAGHEADER *)clone->data; // tag ID dst_tag->id = src_tag->id; // tag key if(src_tag->key) { dst_tag->key = (char*)malloc((strlen(src_tag->key) + 1) * sizeof(char)); if(!dst_tag->key) { throw FI_MSG_ERROR_MEMORY; } strcpy(dst_tag->key, src_tag->key); } // tag description if(src_tag->description) { dst_tag->description = (char*)malloc((strlen(src_tag->description) + 1) * sizeof(char)); if(!dst_tag->description) { throw FI_MSG_ERROR_MEMORY; } strcpy(dst_tag->description, src_tag->description); } // tag data type dst_tag->type = src_tag->type; // tag count dst_tag->count = src_tag->count; // tag length dst_tag->length = src_tag->length; // tag value dst_tag->value = (BYTE*)malloc(src_tag->length * sizeof(BYTE)); if(!dst_tag->value) { throw FI_MSG_ERROR_MEMORY; } memcpy(dst_tag->value, src_tag->value, src_tag->length); return clone; } catch(const char *message) { FreeImage_DeleteTag(clone); FreeImage_OutputMessageProc(FIF_UNKNOWN, message); return NULL; } }
/** Convert a processed raw image to a FIBITMAP @param image Processed raw image @return Returns the converted dib if successfull, returns NULL otherwise @see libraw_LoadEmbeddedPreview */ static FIBITMAP * libraw_ConvertProcessedImageToDib(libraw_processed_image_t *image) { FIBITMAP *dib = NULL; try { unsigned width = image->width; unsigned height = image->height; unsigned bpp = image->bits; if(bpp == 16) { // allocate output dib dib = FreeImage_AllocateT(FIT_RGB16, width, height); if(!dib) { throw FI_MSG_ERROR_DIB_MEMORY; } // write data WORD *raw_data = (WORD*)image->data; for(unsigned y = 0; y < height; y++) { FIRGB16 *output = (FIRGB16*)FreeImage_GetScanLine(dib, height - 1 - y); for(unsigned x = 0; x < width; x++) { output[x].red = raw_data[0]; output[x].green = raw_data[1]; output[x].blue = raw_data[2]; raw_data += 3; } } } else if(bpp == 8) { // allocate output dib dib = FreeImage_AllocateT(FIT_BITMAP, width, height, 24); if(!dib) { throw FI_MSG_ERROR_DIB_MEMORY; } // write data BYTE *raw_data = (BYTE*)image->data; for(unsigned y = 0; y < height; y++) { RGBTRIPLE *output = (RGBTRIPLE*)FreeImage_GetScanLine(dib, height - 1 - y); for(unsigned x = 0; x < width; x++) { output[x].rgbtRed = raw_data[0]; output[x].rgbtGreen = raw_data[1]; output[x].rgbtBlue = raw_data[2]; raw_data += 3; } } } return dib; } catch(const char *text) { FreeImage_Unload(dib); FreeImage_OutputMessageProc(s_format_id, text); return NULL; } }
/** Read JPEG_APP1 marker (Exif profile) @param dib Input FIBITMAP @param dataptr Pointer to the APP1 marker @param datalen APP1 marker length @return Returns TRUE if successful, FALSE otherwise */ BOOL jpeg_read_exif_profile(FIBITMAP *dib, const BYTE *dataptr, unsigned int datalen) { // marker identifying string for Exif = "Exif\0\0" BYTE exif_signature[6] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 }; BYTE lsb_first[4] = { 0x49, 0x49, 0x2A, 0x00 }; // Intel order BYTE msb_first[4] = { 0x4D, 0x4D, 0x00, 0x2A }; // Motorola order unsigned int length = datalen; BYTE *profile = (BYTE*)dataptr; // verify the identifying string if(memcmp(exif_signature, profile, sizeof(exif_signature)) == 0) { // Exif profile profile += sizeof(exif_signature); length -= sizeof(exif_signature); // check the endianess order BOOL bMotorolaOrder = TRUE; if(memcmp(profile, lsb_first, sizeof(lsb_first)) == 0) { // Exif section in Intel order bMotorolaOrder = FALSE; } else { if(memcmp(profile, msb_first, sizeof(msb_first)) == 0) { // Exif section in Motorola order bMotorolaOrder = TRUE; } else { // Invalid Exif alignment marker return FALSE; } } // this is the offset to the first IFD unsigned long first_offset = ReadUint32(bMotorolaOrder, profile + 4); if (first_offset < 8 || first_offset > 16) { // This is usually set to 8 // but PENTAX Optio 230 has it set differently, and uses it as offset. FreeImage_OutputMessageProc(FIF_JPEG, "Exif: Suspicious offset of first IFD value"); return FALSE; } // process Exif directories return jpeg_read_exif_dir(dib, profile, first_offset, length, bMotorolaOrder); } return FALSE; }
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; }
/** Convert a processed raw data array to a FIBITMAP @param RawProcessor LibRaw handle containing the processed raw image @return Returns the converted dib if successfull, returns NULL otherwise */ static FIBITMAP * libraw_ConvertProcessedRawToDib(LibRaw *RawProcessor) { FIBITMAP *dib = NULL; int width, height, colors, bpp; try { int bgr = 0; // pixel copy order: RGB if (bgr == 0) and BGR otherwise // get image info RawProcessor->get_mem_image_format(&width, &height, &colors, &bpp); // only 3-color images supported... if(colors != 3) { throw "LibRaw : only 3-color images supported"; } if(bpp == 16) { // allocate output dib dib = FreeImage_AllocateT(FIT_RGB16, width, height); if(!dib) { throw FI_MSG_ERROR_DIB_MEMORY; } } else if(bpp == 8) { #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR bgr = 1; // only useful for FIT_BITMAP types #endif // allocate output dib dib = FreeImage_AllocateT(FIT_BITMAP, width, height, 24); if(!dib) { throw FI_MSG_ERROR_DIB_MEMORY; } } // copy post-processed bitmap data into FIBITMAP buffer if(RawProcessor->copy_mem_image(FreeImage_GetBits(dib), FreeImage_GetPitch(dib), bgr) != LIBRAW_SUCCESS) { throw "LibRaw : failed to copy data into dib"; } // flip vertically FreeImage_FlipVertical(dib); return dib; } catch(const char *text) { FreeImage_Unload(dib); FreeImage_OutputMessageProc(s_format_id, text); return NULL; } }
/** Load raw data and convert to FIBITMAP @param RawProcessor Libraw handle @param bitspersample Output bitdepth (8- or 16-bit) @return Returns the loaded dib if successfull, returns NULL otherwise */ static FIBITMAP * libraw_LoadRawData(LibRaw *RawProcessor, int bitspersample) { FIBITMAP *dib = NULL; try { // set decoding parameters // ----------------------- // (-6) 16-bit or 8-bit RawProcessor->imgdata.params.output_bps = bitspersample; // (-g power toe_slope) if(bitspersample == 16) { // set -g 1 1 for linear curve RawProcessor->imgdata.params.gamm[0] = 1; RawProcessor->imgdata.params.gamm[1] = 1; } else if(bitspersample == 8) { // by default settings for rec. BT.709 are used: power 2.222 (i.e. gamm[0]=1/2.222) and slope 4.5 RawProcessor->imgdata.params.gamm[0] = 1/2.222; RawProcessor->imgdata.params.gamm[1] = 4.5; } // (-W) Don't use automatic increase of brightness by histogram RawProcessor->imgdata.params.no_auto_bright = 1; // (-a) Use automatic white balance obtained after averaging over the entire image RawProcessor->imgdata.params.use_auto_wb = 1; // (-q 3) Adaptive homogeneity-directed demosaicing algorithm (AHD) RawProcessor->imgdata.params.user_qual = 3; // ----------------------- // unpack data if(RawProcessor->unpack() != LIBRAW_SUCCESS) { throw "LibRaw : failed to unpack data"; } // process data (... most consuming task ...) if(RawProcessor->dcraw_process() != LIBRAW_SUCCESS) { throw "LibRaw : failed to process data"; } // retrieve processed image dib = libraw_ConvertProcessedRawToDib(RawProcessor); return dib; } catch(const char *text) { FreeImage_OutputMessageProc(s_format_id, text); return NULL; } }
mng_bool mymngerror(mng_handle mng, mng_int32 code, mng_int8 severity, mng_chunkid chunktype, mng_uint32 chunkseq, mng_int32 extra1, mng_int32 extra2, mng_pchar text) { char msg[256]; if((code == MNG_SEQUENCEERROR) && (chunktype == MNG_UINT_TERM)) { // ignore sequence error for TERM return MNG_TRUE; } if(text) { // text can be null depending on compiler options sprintf(msg, "Error reported by libmng (%d)\r\n\r\n%s", code, text); } else { sprintf(msg, "Error %d reported by libmng", code); } FreeImage_OutputMessageProc(s_format_id, msg); return MNG_FALSE; }
/** Compresses a source buffer into a target buffer, using the ZLib library. Upon entry, target_size is the total size of the destination buffer, which must be at least 0.1% larger than source_size plus 12 bytes. @param target Destination buffer @param target_size Size of the destination buffer, in bytes @param source Source buffer @param source_size Size of the source buffer, in bytes @return Returns the actual size of the compressed buffer, returns 0 if an error occured @see FreeImage_ZLibUncompress */ DWORD DLL_CALLCONV FreeImage_ZLibCompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) { uLongf dest_len = (uLongf)target_size; int zerr = compress(target, &dest_len, source, source_size); switch(zerr) { case Z_MEM_ERROR: // not enough memory case Z_BUF_ERROR: // not enough room in the output buffer FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr)); return 0; case Z_OK: return dest_len; } return 0; }
/** Decompresses a source buffer into a target buffer, using the ZLib library. Upon entry, target_size is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library. @param target Destination buffer @param target_size Size of the destination buffer, in bytes @param source Source buffer @param source_size Size of the source buffer, in bytes @return Returns the actual size of the uncompressed buffer, returns 0 if an error occured @see FreeImage_ZLibCompress */ DWORD DLL_CALLCONV FreeImage_ZLibUncompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size) { DWORD dest_len = target_size; int zerr = uncompress(target, &dest_len, source, source_size); switch(zerr) { case Z_MEM_ERROR: // not enough memory case Z_BUF_ERROR: // not enough room in the output buffer case Z_DATA_ERROR: // input data was corrupted FreeImage_OutputMessageProc(FIF_UNKNOWN, "Zlib error : %s", zError(zerr)); return 0; case Z_OK: return dest_len; } return 0; }
/** Set the preview image using the dib embedded thumbnail */ static BOOL SetPreviewImage(FIBITMAP *dib, Imf::Header& header) { if(!FreeImage_GetThumbnail(dib)) { return FALSE; } FIBITMAP* thumbnail = FreeImage_GetThumbnail(dib); if((FreeImage_GetImageType(thumbnail) != FIT_BITMAP) || (FreeImage_GetBPP(thumbnail) != 32)) { // invalid thumbnail - ignore it FreeImage_OutputMessageProc(s_format_id, FI_MSG_WARNING_INVALID_THUMBNAIL); } else { const unsigned thWidth = FreeImage_GetWidth(thumbnail); const unsigned thHeight = FreeImage_GetHeight(thumbnail); Imf::PreviewImage preview(thWidth, thHeight); // copy thumbnail to 32-bit RGBA preview image const BYTE* src_line = FreeImage_GetScanLine(thumbnail, thHeight - 1); Imf::PreviewRgba* dst_line = preview.pixels(); const unsigned srcPitch = FreeImage_GetPitch(thumbnail); for (unsigned y = 0; y < thHeight; y++) { const RGBQUAD* src_pixel = (RGBQUAD*)src_line; Imf::PreviewRgba* dst_pixel = dst_line; for(unsigned x = 0; x < thWidth; x++) { dst_pixel->r = src_pixel->rgbRed; dst_pixel->g = src_pixel->rgbGreen; dst_pixel->b = src_pixel->rgbBlue; dst_pixel->a = src_pixel->rgbReserved; src_pixel++; dst_pixel++; } src_line -= srcPitch; dst_line += thWidth; } header.setPreviewImage(preview); } return TRUE; }
BOOL DLL_CALLCONV FreeImage_SaveToMemory(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, FIMEMORY *stream, int flags) { if (stream) { FreeImageIO io; SetMemoryIO(&io); FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(stream->data); if(mem_header->delete_me == TRUE) { return FreeImage_SaveToHandle(fif, dib, &io, (fi_handle)stream, flags); } else { // do not save in a user buffer FreeImage_OutputMessageProc(fif, "Memory buffer is read only"); } } return FALSE; }
/** Writes data to a memory stream. @param buffer Pointer to data to be written @param size Item size in bytes @param count Maximum number of items to be written @param stream Pointer to FIMEMORY structure @return Returns the number of full items actually written, which may be less than count if an error occurs */ unsigned DLL_CALLCONV FreeImage_WriteMemory(const void *buffer, unsigned size, unsigned count, FIMEMORY *stream) { if (stream != NULL) { FreeImageIO io; SetMemoryIO(&io); FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(((FIMEMORY*)stream)->data); if(mem_header->delete_me == TRUE) { return io.write_proc((void *)buffer, size, count, stream); } else { // do not write in a user buffer FreeImage_OutputMessageProc(FIF_UNKNOWN, "Memory buffer is read only"); } } return 0; }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { FIBITMAP *dib = NULL; if(handle) { try { rgbeHeaderInfo header_info; unsigned width, height; // Read the header if(rgbe_ReadHeader(io, handle, &width, &height, &header_info) == FALSE) return NULL; // allocate a RGBF image dib = FreeImage_AllocateT(FIT_RGBF, width, height); if(!dib) { throw "Memory allocation failed"; } // read the image pixels and fill the dib for(unsigned y = 0; y < height; y++) { FIRGBF *scanline = (FIRGBF*)FreeImage_GetScanLine(dib, height - 1 - y); if(!rgbe_ReadPixels_RLE(io, handle, scanline, width, 1)) { FreeImage_Unload(dib); return NULL; } } // set the metadata as comments rgbe_ReadMetadata(dib, &header_info); } catch(const char *text) { if(dib != NULL) { FreeImage_Unload(dib); } FreeImage_OutputMessageProc(s_format_id, text); } } return dib; }
FIBITMAP* DLL_CALLCONV FIA_FFT(FIBITMAP *src) { if(!src) return NULL; // Convert from src_type to FIT_BITMAP FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(src); switch (src_type) { case FIT_BITMAP: // standard image: 1-, 4-, 8-, 16-, 24-, 32-bit if(FreeImage_GetBPP(src) == 8) return fftUCharImage.FFT(src); break; case FIT_UINT16: // array of unsigned short: unsigned 16-bit return fftUShortImage.FFT(src); case FIT_INT16: // array of short: signed 16-bit return fftShortImage.FFT(src); case FIT_UINT32: // array of unsigned long: unsigned 32-bit return fftULongImage.FFT(src); case FIT_INT32: // array of long: signed 32-bit return fftLongImage.FFT(src); case FIT_FLOAT: // array of float: 32-bit return fftFloatImage.FFT(src); case FIT_DOUBLE: // array of double: 64-bit return fftDoubleImage.FFT(src); default: break; } FreeImage_OutputMessageProc(FIF_UNKNOWN, "FREE_IMAGE_TYPE: Unable to perform FFT for type %d.", src_type); return NULL; }
BOOL fipWinImage::copyFromBitmap(HBITMAP hbmp) { if(hbmp) { int Success; BITMAP bm; // Get informations about the bitmap GetObject(hbmp, sizeof(BITMAP), (LPSTR) &bm); // Create the image setSize(FIT_BITMAP, (WORD)bm.bmWidth, (WORD)bm.bmHeight, (WORD)bm.bmBitsPixel); // The GetDIBits function clears the biClrUsed and biClrImportant BITMAPINFO members (dont't know why) // So we save these infos below. This is needed for palettized images only. int nColors = FreeImage_GetColorsUsed(_dib); // Create a device context for the bitmap HDC dc = GetDC(NULL); // Copy the pixels Success = GetDIBits(dc, // handle to DC hbmp, // handle to bitmap 0, // first scan line to set FreeImage_GetHeight(_dib), // number of scan lines to copy FreeImage_GetBits(_dib), // array for bitmap bits FreeImage_GetInfo(_dib), // bitmap data buffer DIB_RGB_COLORS // RGB ); if(Success == 0) { FreeImage_OutputMessageProc(FIF_UNKNOWN, "Error : GetDIBits failed"); ReleaseDC(NULL, dc); return FALSE; } ReleaseDC(NULL, dc); // restore BITMAPINFO members FreeImage_GetInfoHeader(_dib)->biClrUsed = nColors; FreeImage_GetInfoHeader(_dib)->biClrImportant = nColors; return TRUE; } return FALSE; }
BOOL DLL_CALLCONV FreeImage_JPEGTransform(const char *src_file, const char *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect) { try { // check the src file format if(FreeImage_GetFileType(src_file) != FIF_JPEG) { throw FI_MSG_ERROR_MAGIC_NUMBER; } // setup IO FilenameIO filenameIO; memset(&filenameIO, 0, sizeof(FilenameIO)); filenameIO.src_file = src_file; filenameIO.dst_file = dst_file; // perform the transformation return LosslessTransform(&filenameIO, operation, NULL, perfect); } catch(const char *text) { FreeImage_OutputMessageProc(FIF_JPEG, text); return FALSE; } }
static BOOL getMemIO(FIMEMORY* src_stream, FIMEMORY* dst_stream, FreeImageIO* dst_io, fi_handle* src_handle, fi_handle* dst_handle) { *src_handle = NULL; *dst_handle = NULL; FreeImageIO io; SetMemoryIO (&io); if(dst_stream) { FIMEMORYHEADER *mem_header = (FIMEMORYHEADER*)(dst_stream->data); if(mem_header->delete_me != TRUE) { // do not save in a user buffer FreeImage_OutputMessageProc(FIF_JPEG, "Destination memory buffer is read only"); return FALSE; } } *dst_io = io; *src_handle = src_stream; *dst_handle = dst_stream; return TRUE; }
static BOOL DLL_CALLCONV Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { if(!dib) return FALSE; FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(dib); if(src_type != FIT_RGBF) { FreeImage_OutputMessageProc(s_format_id, "FREE_IMAGE_TYPE: Unable to convert from type %d to type %d.\n No such conversion exists.", src_type, FIT_RGBF); return FALSE; } unsigned width = FreeImage_GetWidth(dib); unsigned height = FreeImage_GetHeight(dib); // write the header rgbeHeaderInfo header_info; memset(&header_info, 0, sizeof(rgbeHeaderInfo)); // fill the header with correct gamma and exposure rgbe_WriteMetadata(dib, &header_info); // fill a comment sprintf(header_info.comment, "# Made with FreeImage %s", FreeImage_GetVersion()); if(!rgbe_WriteHeader(io, handle, width, height, &header_info)) { return FALSE; } // write each scanline for(unsigned y = 0; y < height; y++) { FIRGBF *scanline = (FIRGBF*)FreeImage_GetScanLine(dib, height - 1 - y); if(!rgbe_WritePixels_RLE(io, handle, scanline, width, 1)) { return FALSE; } } return TRUE; }
static BOOL JPEGTransformFromHandle(FreeImageIO* src_io, fi_handle src_handle, FreeImageIO* dst_io, fi_handle dst_handle, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect) { const BOOL onlyReturnCropRect = (dst_io == NULL) || (dst_handle == NULL); const long stream_start = onlyReturnCropRect ? 0 : dst_io->tell_proc(dst_handle); BOOL swappedDim = FALSE; BOOL trimH = FALSE; BOOL trimV = FALSE; // Set up the jpeglib structures jpeg_decompress_struct srcinfo; jpeg_compress_struct dstinfo; jpeg_error_mgr jsrcerr, jdsterr; jvirt_barray_ptr *src_coef_arrays = NULL; jvirt_barray_ptr *dst_coef_arrays = NULL; // Support for copying optional markers from source to destination file JCOPY_OPTION copyoption; // Image transformation options jpeg_transform_info transfoptions; // Initialize structures memset(&srcinfo, 0, sizeof(srcinfo)); memset(&jsrcerr, 0, sizeof(jsrcerr)); memset(&jdsterr, 0, sizeof(jdsterr)); memset(&dstinfo, 0, sizeof(dstinfo)); memset(&transfoptions, 0, sizeof(transfoptions)); // Copy all extra markers from source file copyoption = JCOPYOPT_ALL; // Set up default JPEG parameters transfoptions.force_grayscale = FALSE; transfoptions.crop = FALSE; // Select the transform option switch(operation) { case FIJPEG_OP_FLIP_H: // horizontal flip transfoptions.transform = JXFORM_FLIP_H; trimH = TRUE; break; case FIJPEG_OP_FLIP_V: // vertical flip transfoptions.transform = JXFORM_FLIP_V; trimV = TRUE; break; case FIJPEG_OP_TRANSPOSE: // transpose across UL-to-LR axis transfoptions.transform = JXFORM_TRANSPOSE; swappedDim = TRUE; break; case FIJPEG_OP_TRANSVERSE: // transpose across UR-to-LL axis transfoptions.transform = JXFORM_TRANSVERSE; trimH = TRUE; trimV = TRUE; swappedDim = TRUE; break; case FIJPEG_OP_ROTATE_90: // 90-degree clockwise rotation transfoptions.transform = JXFORM_ROT_90; trimH = TRUE; swappedDim = TRUE; break; case FIJPEG_OP_ROTATE_180: // 180-degree rotation trimH = TRUE; trimV = TRUE; transfoptions.transform = JXFORM_ROT_180; break; case FIJPEG_OP_ROTATE_270: // 270-degree clockwise (or 90 ccw) transfoptions.transform = JXFORM_ROT_270; trimV = TRUE; swappedDim = TRUE; break; default: case FIJPEG_OP_NONE: // no transformation transfoptions.transform = JXFORM_NONE; break; } // (perfect == TRUE) ==> fail if there is non-transformable edge blocks transfoptions.perfect = (perfect == TRUE) ? TRUE : FALSE; // Drop non-transformable edge blocks: trim off any partial edge MCUs that the transform can't handle. transfoptions.trim = TRUE; try { // Initialize the JPEG decompression object with default error handling srcinfo.err = jpeg_std_error(&jsrcerr); srcinfo.err->error_exit = ls_jpeg_error_exit; srcinfo.err->output_message = ls_jpeg_output_message; jpeg_create_decompress(&srcinfo); // Initialize the JPEG compression object with default error handling dstinfo.err = jpeg_std_error(&jdsterr); dstinfo.err->error_exit = ls_jpeg_error_exit; dstinfo.err->output_message = ls_jpeg_output_message; jpeg_create_compress(&dstinfo); // Specify data source for decompression jpeg_freeimage_src(&srcinfo, src_handle, src_io); // Enable saving of extra markers that we want to copy jcopy_markers_setup(&srcinfo, copyoption); // Read the file header jpeg_read_header(&srcinfo, TRUE); // crop option char crop[64]; const BOOL hasCrop = getCropString(crop, left, top, right, bottom, swappedDim ? srcinfo.image_height : srcinfo.image_width, swappedDim ? srcinfo.image_width : srcinfo.image_height); if(hasCrop) { if(!jtransform_parse_crop_spec(&transfoptions, crop)) { FreeImage_OutputMessageProc(FIF_JPEG, "Bogus crop argument %s", crop); throw(1); } } // Any space needed by a transform option must be requested before // jpeg_read_coefficients so that memory allocation will be done right // Prepare transformation workspace // Fails right away if perfect flag is TRUE and transformation is not perfect if( !jtransform_request_workspace(&srcinfo, &transfoptions) ) { FreeImage_OutputMessageProc(FIF_JPEG, "Transformation is not perfect"); throw(1); } if(left || top) { // compute left and top offsets, it's a bit tricky, taking into account both // transform, which might have trimed the image, // and crop itself, which is adjusted to lie on a iMCU boundary const int fullWidth = swappedDim ? srcinfo.image_height : srcinfo.image_width; const int fullHeight = swappedDim ? srcinfo.image_width : srcinfo.image_height; int transformedFullWidth = fullWidth; int transformedFullHeight = fullHeight; if(trimH && transformedFullWidth/transfoptions.iMCU_sample_width > 0) { transformedFullWidth = (transformedFullWidth/transfoptions.iMCU_sample_width) * transfoptions.iMCU_sample_width; } if(trimV && transformedFullHeight/transfoptions.iMCU_sample_height > 0) { transformedFullHeight = (transformedFullHeight/transfoptions.iMCU_sample_height) * transfoptions.iMCU_sample_height; } const int trimmedWidth = fullWidth - transformedFullWidth; const int trimmedHeight = fullHeight - transformedFullHeight; if(left) { *left = trimmedWidth + transfoptions.x_crop_offset * transfoptions.iMCU_sample_width; } if(top) { *top = trimmedHeight + transfoptions.y_crop_offset * transfoptions.iMCU_sample_height; } } if(right) { *right = (left ? *left : 0) + transfoptions.output_width; } if(bottom) { *bottom = (top ? *top : 0) + transfoptions.output_height; } // if only the crop rect is requested, we are done if(onlyReturnCropRect) { jpeg_destroy_compress(&dstinfo); jpeg_destroy_decompress(&srcinfo); return TRUE; } // Read source file as DCT coefficients src_coef_arrays = jpeg_read_coefficients(&srcinfo); // Initialize destination compression parameters from source values jpeg_copy_critical_parameters(&srcinfo, &dstinfo); // Adjust destination parameters if required by transform options; // also find out which set of coefficient arrays will hold the output dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transfoptions); // Note: we assume that jpeg_read_coefficients consumed all input // until JPEG_REACHED_EOI, and that jpeg_finish_decompress will // only consume more while (! cinfo->inputctl->eoi_reached). // We cannot call jpeg_finish_decompress here since we still need the // virtual arrays allocated from the source object for processing. if(src_handle == dst_handle) { dst_io->seek_proc(dst_handle, stream_start, SEEK_SET); } // Specify data destination for compression jpeg_freeimage_dst(&dstinfo, dst_handle, dst_io); // Start compressor (note no image data is actually written here) jpeg_write_coefficients(&dstinfo, dst_coef_arrays); // Copy to the output file any extra markers that we want to preserve jcopy_markers_execute(&srcinfo, &dstinfo, copyoption); // Execute image transformation, if any jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, &transfoptions); // Finish compression and release memory jpeg_finish_compress(&dstinfo); jpeg_destroy_compress(&dstinfo); jpeg_finish_decompress(&srcinfo); jpeg_destroy_decompress(&srcinfo); } catch(...) { jpeg_destroy_compress(&dstinfo); jpeg_destroy_decompress(&srcinfo); return FALSE; } return TRUE; }
FIBITMAP* DLL_CALLCONV FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_linear) { FIBITMAP *dst = NULL; if(!FreeImage_HasPixels(src)) return NULL; // convert from src_type to dst_type const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(src); if(src_type == dst_type) { return FreeImage_Clone(src); } const unsigned src_bpp = FreeImage_GetBPP(src); switch(src_type) { case FIT_BITMAP: switch(dst_type) { case FIT_UINT16: dst = FreeImage_ConvertToUINT16(src); break; case FIT_INT16: dst = (src_bpp == 8) ? convertByteToShort.convert(src, dst_type) : NULL; break; case FIT_UINT32: dst = (src_bpp == 8) ? convertByteToULong.convert(src, dst_type) : NULL; break; case FIT_INT32: dst = (src_bpp == 8) ? convertByteToLong.convert(src, dst_type) : NULL; break; case FIT_FLOAT: dst = FreeImage_ConvertToFloat(src); break; case FIT_DOUBLE: dst = (src_bpp == 8) ? convertByteToDouble.convert(src, dst_type) : NULL; break; case FIT_COMPLEX: dst = (src_bpp == 8) ? convertByteToComplex.convert(src) : NULL; break; case FIT_RGB16: dst = FreeImage_ConvertToRGB16(src); break; case FIT_RGBA16: dst = FreeImage_ConvertToRGBA16(src); break; case FIT_RGBF: dst = FreeImage_ConvertToRGBF(src); break; case FIT_RGBAF: dst = FreeImage_ConvertToRGBAF(src); break; } break; case FIT_UINT16: switch(dst_type) { case FIT_BITMAP: dst = FreeImage_ConvertToStandardType(src, scale_linear); break; case FIT_INT16: break; case FIT_UINT32: break; case FIT_INT32: break; case FIT_FLOAT: dst = FreeImage_ConvertToFloat(src); break; case FIT_DOUBLE: dst = convertUShortToDouble.convert(src, dst_type); break; case FIT_COMPLEX: dst = convertUShortToComplex.convert(src); break; case FIT_RGB16: dst = FreeImage_ConvertToRGB16(src); break; case FIT_RGBA16: dst = FreeImage_ConvertToRGBA16(src); break; case FIT_RGBF: dst = FreeImage_ConvertToRGBF(src); break; case FIT_RGBAF: dst = FreeImage_ConvertToRGBAF(src); break; } break; case FIT_INT16: switch(dst_type) { case FIT_BITMAP: dst = FreeImage_ConvertToStandardType(src, scale_linear); break; case FIT_UINT16: break; case FIT_UINT32: break; case FIT_INT32: break; case FIT_FLOAT: dst = convertShortToFloat.convert(src, dst_type); break; case FIT_DOUBLE: dst = convertShortToDouble.convert(src, dst_type); break; case FIT_COMPLEX: dst = convertShortToComplex.convert(src); break; case FIT_RGB16: break; case FIT_RGBA16: break; case FIT_RGBF: break; case FIT_RGBAF: break; } break; case FIT_UINT32: switch(dst_type) { case FIT_BITMAP: dst = FreeImage_ConvertToStandardType(src, scale_linear); break; case FIT_UINT16: break; case FIT_INT16: break; case FIT_INT32: break; case FIT_FLOAT: dst = convertULongToFloat.convert(src, dst_type); break; case FIT_DOUBLE: dst = convertULongToDouble.convert(src, dst_type); break; case FIT_COMPLEX: dst = convertULongToComplex.convert(src); break; case FIT_RGB16: break; case FIT_RGBA16: break; case FIT_RGBF: break; case FIT_RGBAF: break; } break; case FIT_INT32: switch(dst_type) { case FIT_BITMAP: dst = FreeImage_ConvertToStandardType(src, scale_linear); break; case FIT_UINT16: break; case FIT_INT16: break; case FIT_UINT32: break; case FIT_FLOAT: dst = convertLongToFloat.convert(src, dst_type); break; case FIT_DOUBLE: dst = convertLongToDouble.convert(src, dst_type); break; case FIT_COMPLEX: dst = convertLongToComplex.convert(src); break; case FIT_RGB16: break; case FIT_RGBA16: break; case FIT_RGBF: break; case FIT_RGBAF: break; } break; case FIT_FLOAT: switch(dst_type) { case FIT_BITMAP: dst = FreeImage_ConvertToStandardType(src, scale_linear); break; case FIT_UINT16: break; case FIT_INT16: break; case FIT_UINT32: break; case FIT_INT32: break; case FIT_DOUBLE: dst = convertFloatToDouble.convert(src, dst_type); break; case FIT_COMPLEX: dst = convertFloatToComplex.convert(src); break; case FIT_RGB16: break; case FIT_RGBA16: break; case FIT_RGBF: dst = FreeImage_ConvertToRGBF(src); break; case FIT_RGBAF: dst = FreeImage_ConvertToRGBAF(src); break; } break; case FIT_DOUBLE: switch(dst_type) { case FIT_BITMAP: dst = FreeImage_ConvertToStandardType(src, scale_linear); break; case FIT_UINT16: break; case FIT_INT16: break; case FIT_UINT32: break; case FIT_INT32: break; case FIT_FLOAT: break; case FIT_COMPLEX: dst = convertDoubleToComplex.convert(src); break; case FIT_RGB16: break; case FIT_RGBA16: break; case FIT_RGBF: break; case FIT_RGBAF: break; } break; case FIT_COMPLEX: switch(dst_type) { case FIT_BITMAP: break; case FIT_UINT16: break; case FIT_INT16: break; case FIT_UINT32: break; case FIT_INT32: break; case FIT_FLOAT: break; case FIT_DOUBLE: break; case FIT_RGB16: break; case FIT_RGBA16: break; case FIT_RGBF: break; case FIT_RGBAF: break; } break; case FIT_RGB16: switch(dst_type) { case FIT_BITMAP: dst = FreeImage_ConvertTo24Bits(src); break; case FIT_UINT16: dst = FreeImage_ConvertToUINT16(src); break; case FIT_INT16: break; case FIT_UINT32: break; case FIT_INT32: break; case FIT_FLOAT: dst = FreeImage_ConvertToFloat(src); break; case FIT_DOUBLE: break; case FIT_COMPLEX: break; case FIT_RGBA16: dst = FreeImage_ConvertToRGBA16(src); break; case FIT_RGBF: dst = FreeImage_ConvertToRGBF(src); break; case FIT_RGBAF: dst = FreeImage_ConvertToRGBAF(src); break; } break; case FIT_RGBA16: switch(dst_type) { case FIT_BITMAP: dst = FreeImage_ConvertTo32Bits(src); break; case FIT_UINT16: dst = FreeImage_ConvertToUINT16(src); break; case FIT_INT16: break; case FIT_UINT32: break; case FIT_INT32: break; case FIT_FLOAT: dst = FreeImage_ConvertToFloat(src); break; case FIT_DOUBLE: break; case FIT_COMPLEX: break; case FIT_RGB16: dst = FreeImage_ConvertToRGB16(src); break; case FIT_RGBF: dst = FreeImage_ConvertToRGBF(src); break; case FIT_RGBAF: dst = FreeImage_ConvertToRGBAF(src); break; } break; case FIT_RGBF: switch(dst_type) { case FIT_BITMAP: break; case FIT_UINT16: break; case FIT_INT16: break; case FIT_UINT32: break; case FIT_INT32: break; case FIT_FLOAT: dst = FreeImage_ConvertToFloat(src); break; case FIT_DOUBLE: break; case FIT_COMPLEX: break; case FIT_RGB16: break; case FIT_RGBA16: break; case FIT_RGBAF: dst = FreeImage_ConvertToRGBAF(src); break; } break; case FIT_RGBAF: switch(dst_type) { case FIT_BITMAP: break; case FIT_UINT16: break; case FIT_INT16: break; case FIT_UINT32: break; case FIT_INT32: break; case FIT_FLOAT: dst = FreeImage_ConvertToFloat(src); break; case FIT_DOUBLE: break; case FIT_COMPLEX: break; case FIT_RGB16: break; case FIT_RGBA16: break; case FIT_RGBF: dst = FreeImage_ConvertToRGBF(src); break; } break; } if(NULL == dst) { FreeImage_OutputMessageProc(FIF_UNKNOWN, "FREE_IMAGE_TYPE: Unable to convert from type %d to type %d.\n No such conversion exists.", src_type, dst_type); } return dst; }
/** OpenJPEG Warning callback */ static void jp2_warning_callback(const char *msg, void *client_data) { FreeImage_OutputMessageProc(s_format_id, "Warning: %s", msg); }
/** OpenJPEG Error callback */ static void jp2_error_callback(const char *msg, void *client_data) { FreeImage_OutputMessageProc(s_format_id, "Error: %s", msg); }
static BOOL DLL_CALLCONV Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { if ((dib) && (handle)) { BOOL bSuccess; opj_cparameters_t parameters; // compression parameters opj_event_mgr_t event_mgr; // event manager opj_image_t *image = NULL; // image to encode opj_cinfo_t* cinfo = NULL; // codec context opj_cio_t *cio = NULL; // memory byte stream // configure the event callbacks memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); event_mgr.error_handler = jp2_error_callback; event_mgr.warning_handler = jp2_warning_callback; event_mgr.info_handler = NULL; // set encoding parameters to default values opj_set_default_encoder_parameters(¶meters); parameters.tcp_numlayers = 0; // if no rate entered, apply a 16:1 rate by default if(flags == JP2_DEFAULT) { parameters.tcp_rates[0] = (float)16; } else { // for now, the flags parameter is only used to specify the rate parameters.tcp_rates[0] = (float)flags; } parameters.tcp_numlayers++; parameters.cp_disto_alloc = 1; try { // convert the dib to a OpenJPEG image image = FIBITMAPToJ2KImage(s_format_id, dib, ¶meters); if(!image) return FALSE; // encode the destination image // get a J2K compressor handle cinfo = opj_create_compress(CODEC_JP2); // catch events using our callbacks opj_set_event_mgr((opj_common_ptr)cinfo, &event_mgr, NULL); // setup the encoder parameters using the current image and using user parameters opj_setup_encoder(cinfo, ¶meters, image); // open a byte stream for writing, allocate memory for all tiles cio = opj_cio_open((opj_common_ptr)cinfo, NULL, 0); // encode the image bSuccess = opj_encode(cinfo, cio, image, NULL/*parameters.index*/); if (!bSuccess) { throw "Failed to encode image"; } int codestream_length = cio_tell(cio); // write the buffer to user's IO handle io->write_proc(cio->buffer, 1, codestream_length, handle); // close and free the byte stream opj_cio_close(cio); // free remaining compression structures opj_destroy_compress(cinfo); // free image data opj_image_destroy(image); return TRUE; } catch (const char *text) { if(cio) opj_cio_close(cio); if(cinfo) opj_destroy_compress(cinfo); if(image) opj_image_destroy(image); FreeImage_OutputMessageProc(s_format_id, text); return FALSE; } } return FALSE; }