BOOL DLL_CALLCONV FreeImage_SaveMultiBitmapToHandle(FREE_IMAGE_FORMAT fif, FIMULTIBITMAP *bitmap, FreeImageIO *io, fi_handle handle, int flags) { if(!bitmap || !bitmap->data || !io || !handle) { return FALSE; } BOOL success = TRUE; // retrieve the plugin list to find the node belonging to this plugin PluginList *list = FreeImage_GetPluginList(); if (list) { PluginNode *node = list->FindNodeFromFIF(fif); if(node) { MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap); // dst data void *data = FreeImage_Open(node, io, handle, FALSE); // src data void *data_read = NULL; if(header->handle) { // open src header->io->seek_proc(header->handle, 0, SEEK_SET); data_read = FreeImage_Open(header->node, header->io, header->handle, TRUE); } // write all the pages to the file using handle and io int count = 0; for (BlockListIterator i = header->m_blocks.begin(); i != header->m_blocks.end(); i++) { if (success) { switch((*i)->m_type) { case BLOCK_CONTINUEUS: { BlockContinueus *block = (BlockContinueus *)(*i); for (int j = block->m_start; j <= block->m_end; j++) { // load the original source data FIBITMAP *dib = header->node->m_plugin->load_proc(header->io, header->handle, j, header->load_flags, data_read); // save the data success = node->m_plugin->save_proc(io, dib, handle, count, flags, data); count++; FreeImage_Unload(dib); } break; } case BLOCK_REFERENCE: { BlockReference *ref = (BlockReference *)(*i); // read the compressed data BYTE *compressed_data = (BYTE*)malloc(ref->m_size * sizeof(BYTE)); header->m_cachefile->readFile((BYTE *)compressed_data, ref->m_reference, ref->m_size); // uncompress the data FIMEMORY *hmem = FreeImage_OpenMemory(compressed_data, ref->m_size); FIBITMAP *dib = FreeImage_LoadFromMemory(header->cache_fif, hmem, 0); FreeImage_CloseMemory(hmem); // get rid of the buffer free(compressed_data); // save the data success = node->m_plugin->save_proc(io, dib, handle, count, flags, data); count++; // unload the dib FreeImage_Unload(dib); break; } } } else { break; } } // close the files FreeImage_Close(header->node, header->io, header->handle, data_read); FreeImage_Close(node, io, handle, data); return success; } } return FALSE; }
bool IPLFileIO::loadMemory(void* mem, IPLImage*& image) { FIMEMORY* hmem = (FIMEMORY*) mem; FREE_IMAGE_FORMAT fif = FIF_UNKNOWN; FreeImage_SeekMemory(hmem, 0L, SEEK_SET); fif = FreeImage_GetFileTypeFromMemory(hmem, 0); if(fif == FIF_UNKNOWN) { // always close the memory stream FreeImage_CloseMemory(hmem); return false; } FIBITMAP *dib = FreeImage_LoadFromMemory(fif, hmem); int width = FreeImage_GetWidth(dib); int height = FreeImage_GetHeight(dib); // all files need to be flipped FreeImage_FlipVertical(dib); if(FreeImage_GetBPP(dib) == 8) { // grayscale images // convert to 32 bit FIBITMAP *dib2 = FreeImage_ConvertToGreyscale(dib); // clear old image delete image; // create new instance with the right dimensions image = new IPLImage(IPLData::IMAGE_GRAYSCALE, width, height); for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { BYTE value; FreeImage_GetPixelIndex(dib2, x, y, &value); image->plane(0)->p(x, y) = (value * FACTOR_TO_FLOAT); } } FreeImage_Unload(dib2); } else { // color images // convert to 32 bit FIBITMAP *dib2 = FreeImage_ConvertTo32Bits(dib); // clear old image delete image; // create new instance with the right dimensions image = new IPLImage(IPLData::IMAGE_COLOR, width, height); for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { RGBQUAD rgb; FreeImage_GetPixelColor(dib2, x, y, &rgb); image->plane(0)->p(x, y) = (rgb.rgbRed * FACTOR_TO_FLOAT); // R image->plane(1)->p(x, y) = (rgb.rgbGreen * FACTOR_TO_FLOAT); // G image->plane(2)->p(x, y) = (rgb.rgbBlue * FACTOR_TO_FLOAT); // B } } FreeImage_Unload(dib2); } // always close the memory stream FreeImage_CloseMemory(hmem); // free temporary memory FreeImage_Unload(dib); return true; }
/** Process Exif directory @param dib Input FIBITMAP @param tiffp Pointer to the TIFF header @param offset 0th IFD offset @param length Length of the datafile @param msb_order Endianess order of the datafile @return */ static BOOL jpeg_read_exif_dir(FIBITMAP *dib, const BYTE *tiffp, unsigned long offset, unsigned int length, BOOL msb_order) { WORD de, nde; std::stack<WORD> destack; // directory entries stack std::stack<const BYTE*> ifdstack; // IFD stack std::stack<TagLib::MDMODEL> modelstack; // metadata model stack // Keep a list of already visited IFD to avoid stack overflows // when recursive/cyclic directory structures exist. // This kind of recursive Exif file was encountered with Kodak images coming from // KODAK PROFESSIONAL DCS Photo Desk JPEG Export v3.2 W std::map<DWORD, int> visitedIFD; /* "An Image File Directory (IFD) consists of a 2-byte count of the number of directory entries (i.e. the number of fields), followed by a sequence of 12-byte field entries, followed by a 4-byte offset of the next IFD (or 0 if none)." The "next IFD" (1st IFD) is the thumbnail. */ #define DIR_ENTRY_ADDR(_start, _entry) (_start + 2 + (12 * _entry)) // set the metadata model to Exif TagLib::MDMODEL md_model = TagLib::EXIF_MAIN; // set the pointer to the first IFD (0th IFD) and follow it were it leads. const BYTE *ifd0th = (BYTE*)tiffp + offset; const BYTE *ifdp = ifd0th; de = 0; do { // if there is anything on the stack then pop it off if(!destack.empty()) { ifdp = ifdstack.top(); ifdstack.pop(); de = destack.top(); destack.pop(); md_model = modelstack.top(); modelstack.pop(); } // remember that we've visited this directory and entry so that we don't visit it again later DWORD visited = (DWORD)( (((size_t)ifdp & 0xFFFF) << 16) | (size_t)de ); if(visitedIFD.find(visited) != visitedIFD.end()) { continue; } else { visitedIFD[visited] = 1; // processed } // determine how many entries there are in the current IFD nde = ReadUint16(msb_order, ifdp); for(; de < nde; de++) { char *pde = NULL; // pointer to the directory entry char *pval = NULL; // pointer to the tag value // create a tag FITAG *tag = FreeImage_CreateTag(); if(!tag) return FALSE; // point to the directory entry pde = (char*) DIR_ENTRY_ADDR(ifdp, de); // get the tag ID FreeImage_SetTagID(tag, ReadUint16(msb_order, pde)); // get the tag type WORD tag_type = (WORD)ReadUint16(msb_order, pde + 2); if((tag_type - 1) >= EXIF_NUM_FORMATS) { // a problem occured : delete the tag (not free'd after) FreeImage_DeleteTag(tag); // break out of the for loop break; } FreeImage_SetTagType(tag, (FREE_IMAGE_MDTYPE)tag_type); // get number of components FreeImage_SetTagCount(tag, ReadUint32(msb_order, pde + 4)); // check that tag length (size of the tag value in bytes) will fit in a DWORD unsigned tag_data_width = FreeImage_TagDataWidth(FreeImage_GetTagType(tag)); if (tag_data_width != 0 && FreeImage_GetTagCount(tag) > ~(DWORD)0 / tag_data_width) { FreeImage_DeleteTag(tag); // jump to next entry continue; } FreeImage_SetTagLength(tag, FreeImage_GetTagCount(tag) * tag_data_width); if(FreeImage_GetTagLength(tag) <= 4) { // 4 bytes or less and value is in the dir entry itself pval = pde + 8; } else { // if its bigger than 4 bytes, the directory entry contains an offset // first check if offset exceeds buffer, at this stage FreeImage_GetTagLength may return invalid data DWORD offset_value = ReadUint32(msb_order, pde + 8); if(offset_value > length) { // a problem occured : delete the tag (not free'd after) FreeImage_DeleteTag(tag); // jump to next entry continue; } // now check that length does not exceed the buffer size if(FreeImage_GetTagLength(tag) > length - offset_value) { // a problem occured : delete the tag (not free'd after) FreeImage_DeleteTag(tag); // jump to next entry continue; } pval = (char*)(tiffp + offset_value); } // check for a IFD offset BOOL isIFDOffset = FALSE; switch(FreeImage_GetTagID(tag)) { case TAG_EXIF_OFFSET: case TAG_GPS_OFFSET: case TAG_INTEROP_OFFSET: case TAG_MAKER_NOTE: isIFDOffset = TRUE; break; } if(isIFDOffset) { DWORD sub_offset = 0; TagLib::MDMODEL next_mdmodel = md_model; const BYTE *next_ifd = ifdp; // get offset and metadata model if (FreeImage_GetTagID(tag) == TAG_MAKER_NOTE) { processMakerNote(dib, pval, msb_order, &sub_offset, &next_mdmodel); next_ifd = (BYTE*)pval + sub_offset; } else { processIFDOffset(tag, pval, msb_order, &sub_offset, &next_mdmodel); next_ifd = (BYTE*)tiffp + sub_offset; } if((sub_offset < (DWORD) length) && (next_mdmodel != TagLib::UNKNOWN)) { // push our current directory state onto the stack ifdstack.push(ifdp); // bump to the next entry de++; destack.push(de); // push our current metadata model modelstack.push(md_model); // push new state onto of stack to cause a jump ifdstack.push(next_ifd); destack.push(0); // select a new metadata model modelstack.push(next_mdmodel); // delete the tag as it won't be stored nor deleted in the for() loop FreeImage_DeleteTag(tag); break; // break out of the for loop } else { // unsupported camera model, canon maker tag or something unknown // process as a standard tag processExifTag(dib, tag, pval, msb_order, md_model); } } else { // process as a standard tag processExifTag(dib, tag, pval, msb_order, md_model); } // delete the tag FreeImage_DeleteTag(tag); } // for(nde) // additional thumbnail data is skipped } while (!destack.empty()); // // --- handle thumbnail data --- // const WORD entriesCount0th = ReadUint16(msb_order, ifd0th); DWORD next_offset = ReadUint32(msb_order, DIR_ENTRY_ADDR(ifd0th, entriesCount0th)); if((next_offset == 0) || (next_offset >= length)) { return TRUE; //< no thumbnail } const BYTE* const ifd1st = (BYTE*)tiffp + next_offset; const WORD entriesCount1st = ReadUint16(msb_order, ifd1st); unsigned thCompression = 0; unsigned thOffset = 0; unsigned thSize = 0; for(int e = 0; e < entriesCount1st; e++) { // point to the directory entry const BYTE* base = DIR_ENTRY_ADDR(ifd1st, e); // check for buffer overflow const size_t remaining = (size_t)base + 12 - (size_t)tiffp; if(remaining >= length) { // bad IFD1 directory, ignore it return FALSE; } // get the tag ID WORD tag = ReadUint16(msb_order, base); // get the tag type WORD type = ReadUint16(msb_order, base + sizeof(WORD)); // get number of components DWORD count = ReadUint32(msb_order, base + sizeof(WORD) + sizeof(WORD)); // get the tag value DWORD offset = ReadUint32(msb_order, base + sizeof(WORD) + sizeof(WORD) + sizeof(DWORD)); switch(tag) { case TAG_COMPRESSION: // Tiff Compression Tag (should be COMPRESSION_OJPEG (6), but is not always respected) thCompression = offset; break; case TAG_JPEG_INTERCHANGE_FORMAT: // Tiff JPEGInterchangeFormat Tag thOffset = offset; break; case TAG_JPEG_INTERCHANGE_FORMAT_LENGTH: // Tiff JPEGInterchangeFormatLength Tag thSize = offset; break; // ### X and Y Resolution ignored, orientation ignored case TAG_X_RESOLUTION: // XResolution case TAG_Y_RESOLUTION: // YResolution case TAG_RESOLUTION_UNIT: // ResolutionUnit case TAG_ORIENTATION: // Orientation break; default: break; } } if(/*thCompression != 6 ||*/ thOffset == 0 || thSize == 0) { return TRUE; } if(thOffset + thSize > length) { return TRUE; } // load the thumbnail const BYTE *thLocation = tiffp + thOffset; FIMEMORY* hmem = FreeImage_OpenMemory(const_cast<BYTE*>(thLocation), thSize); FIBITMAP* thumbnail = FreeImage_LoadFromMemory(FIF_JPEG, hmem); FreeImage_CloseMemory(hmem); // store the thumbnail FreeImage_SetThumbnail(dib, thumbnail); // then delete it FreeImage_Unload(thumbnail); return TRUE; }
FOX_DLL int gif2png_bufclose(FIMEMORY * hMemory) { FreeImage_CloseMemory(hMemory) ; // 使用完缓存记得要释放 return 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]; 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; } }
bool FreeImageLoader::load(OS::IStream* file,video::ImageInfo* t2d,video::ETextureType target){ if(m_isDummy) return false; if(!t2d)return false; //image format //pointer to the image, once loaded FIBITMAP *dib(0); //pointer to the image data BYTE* bits(0); //image width and height unsigned int width(0), height(0); byte* data = new byte[file->length()]; //file->read(data,file->length()); DWORD sz=0; FIMEMORY* mem = FreeImage_OpenMemory((BYTE*)data, static_cast<DWORD>(file->length())); //FreeImage_AcquireMemory(mem, &data, &sz); file->read(data, file->length()); //check that the plugin has reading capabilities and load the file if(FreeImage_FIFSupportsReading(m_FTType)) dib = FreeImage_LoadFromMemory(m_FTType, mem); FreeImage_CloseMemory(mem); delete[] data; //if the image failed to load, return failure if(!dib) return false; //retrieve the image data bits = FreeImage_GetBits(dib); //get the image width and height width = FreeImage_GetWidth(dib); height = FreeImage_GetHeight(dib); //if this somehow one of these failed (they shouldn't), return failure if((bits == 0) || (width == 0) || (height == 0)) return false; FREE_IMAGE_TYPE imageType = FreeImage_GetImageType(dib); FREE_IMAGE_COLOR_TYPE colourType = FreeImage_GetColorType(dib); unsigned bpp = FreeImage_GetBPP(dib); video::EPixelFormat imageFormat; switch(imageType) { case FIT_BITMAP: // Standard image type // Perform any colour conversions for greyscale if (colourType == FIC_MINISWHITE || colourType == FIC_MINISBLACK) { FIBITMAP* newBitmap = FreeImage_ConvertToGreyscale(dib); // free old bitmap and replace FreeImage_Unload(dib); dib = newBitmap; // get new formats bpp = FreeImage_GetBPP(dib); colourType = FreeImage_GetColorType(dib); } // Perform any colour conversions for RGB else if (bpp < 8 || colourType == FIC_PALETTE || colourType == FIC_CMYK) { FIBITMAP* newBitmap = FreeImage_ConvertTo24Bits(dib); // free old bitmap and replace FreeImage_Unload(dib); dib = newBitmap; // get new formats bpp = FreeImage_GetBPP(dib); colourType = FreeImage_GetColorType(dib); } // by this stage, 8-bit is greyscale, 16/24/32 bit are RGB[A] switch(bpp) { case 8: imageFormat = video::EPixel_LUMINANCE8; break; case 16: { FIBITMAP* newBitmap = FreeImage_ConvertTo24Bits(dib); // free old bitmap and replace FreeImage_Unload(dib); dib = newBitmap; // get new formats bpp = FreeImage_GetBPP(dib); colourType = FreeImage_GetColorType(dib); imageFormat = video::EPixel_B8G8R8; } break; case 24: imageFormat = video::EPixel_B8G8R8; break; case 32: imageFormat = video::EPixel_B8G8R8A8; break; }; break; case FIT_RGBF: imageFormat = video::EPixel_Float16_RGB; break; case FIT_RGBAF: imageFormat = video::EPixel_Float16_RGBA; break; case FIT_FLOAT: case FIT_UINT16: case FIT_INT16: case FIT_RGB16: case FIT_RGBA16: case FIT_UNKNOWN: case FIT_COMPLEX: case FIT_UINT32: case FIT_INT32: case FIT_DOUBLE: default: gLogManager.log(mT("Loading unsupported image: ")+core::string(file->getStreamName()),ELL_ERROR); break; }; unsigned char* srcData = FreeImage_GetBits(dib); unsigned srcPitch = FreeImage_GetPitch(dib); /* // Final data - invert image and trim pitch at the same time size_t dstPitch = imgData->width * PixelUtil::getNumElemBytes(imgData->format); imgData->size = dstPitch * imgData->height; // Bind output buffer output.bind(OGRE_NEW MemoryDataStream(imgData->size)); uchar* pSrc; uchar* pDst = output->getPtr(); for (size_t y = 0; y < imgData->height; ++y) { pSrc = srcData + (imgData->height - y - 1) * srcPitch; mraySystem::memCopy(pDst, pSrc, dstPitch); pDst += dstPitch; }*/ t2d->createData(math::vector3di(width,height,1),imageFormat); size_t dstPitch = width * video::PixelUtil::getPixelDescription(imageFormat).elemSizeB; uchar* pSrc; uchar* pDst = t2d->imageData; for (size_t y = 0; y < height; ++y) { pSrc = srcData + (height - y - 1) * srcPitch; mraySystem::memCopy(pDst, pSrc, dstPitch); pDst += dstPitch; } FreeImage_Unload(dib); // FreeImage_CloseMemory(fiMem); //return success return true; }
bool StFreeImage::load(const StString& theFilePath, ImageType theImageType, uint8_t* theDataPtr, int theDataSize) { if(!StFreeImage::init()) { setState("FreeImage library is not initialized"); return false; } // reset current data StImage::nullify(); setState(); close(); FREE_IMAGE_FORMAT aFIF = convertToFIF(theImageType); if(theDataPtr != NULL && theDataSize != 0 && aFIF != FIF_UNKNOWN) { FIMEMORY* aFIMemory = FreeImage_OpenMemory(theDataPtr, theDataSize); if(aFIMemory == NULL) { setState("FreeImage library, internal error"); return false; } myDIB = FreeImage_LoadFromMemory(aFIF, aFIMemory, 0); FreeImage_CloseMemory(aFIMemory); } else { // check the file signature and deduce its format #if defined(_WIN32) StStringUtfWide aFilePathWide = theFilePath.toUtfWide(); aFIF = FreeImage_GetFileType(aFilePathWide.toCString(), 0); #else aFIF = FreeImage_GetFileType(theFilePath.toCString(), 0); #endif if(aFIF == FIF_UNKNOWN) { // no signature? try to guess the file format from the file extension #if defined(_WIN32) aFIF = FreeImage_GetFIFFromFilename(aFilePathWide.toCString()); #else aFIF = FreeImage_GetFIFFromFilename(theFilePath.toCString()); #endif } if((aFIF == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading(aFIF)) { setState("FreeImage library does not support image format"); return false; } int loadFlags = 0; if(aFIF == FIF_GIF) { // GIF_PLAYBACK - 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading loadFlags = 2; } else if(aFIF == FIF_ICO) { // ICO_MAKEALPHA - convert to 32bpp and create an alpha channel from the AND-mask when loading loadFlags = 1; } #if defined(_WIN32) myDIB = FreeImage_Load(aFIF, aFilePathWide.toCString(), loadFlags); #else myDIB = FreeImage_Load(aFIF, theFilePath.toCString(), loadFlags); #endif } if(myDIB == NULL) { setState("FreeImage library, loading file failed"); return false; } StImagePlane::ImgFormat stImgFormat = convertFromFreeFormat(FreeImage_GetImageType(myDIB), FreeImage_GetColorType(myDIB), FreeImage_GetBPP(myDIB)); if(stImgFormat == StImagePlane::ImgUNKNOWN) { setState(StString("StFreeImage, image format ") + FreeImage_GetImageType(myDIB) + ", " + FreeImage_GetColorType(myDIB) + " doesn't supported by application"); close(); return false; } setColorModelPacked(stImgFormat); changePlane(0).initWrapper(stImgFormat, FreeImage_GetBits(myDIB), FreeImage_GetWidth(myDIB), FreeImage_GetHeight(myDIB), FreeImage_GetPitch(myDIB)); // FreeImage data always bottom-up... changePlane(0).setTopDown(false); // set debug information StString aDummy, aFileName; StFileNode::getFolderAndFile(theFilePath, aDummy, aFileName); setState(StString("FreeImage library, loaded image '") + aFileName + "' " + getDescription()); // we should not close the file because we create a wrapper over FreeImage native object return true; }
BOOL DLL_CALLCONV FreeImage_CloseMultiBitmap(FIMULTIBITMAP *bitmap, int flags) { if (bitmap) { BOOL success = TRUE; if (bitmap->data) { MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap); if (header->changed) { // open a temp file char spool_name[256]; ReplaceExtension(spool_name, header->m_filename, "fispool"); // open the spool file and the source file FILE *f = fopen(spool_name, "w+b"); void *data = FreeImage_Open(header->node, header->io, (fi_handle)f, FALSE); void *data_read = NULL; if (header->handle) { header->io->seek_proc(header->handle, 0, SEEK_SET); data_read = FreeImage_Open(header->node, header->io, header->handle, TRUE); } // write all the pages to the temp file int count = 0; for (BlockListIterator i = header->m_blocks.begin(); i != header->m_blocks.end(); i++) { if (success) { switch((*i)->m_type) { case BLOCK_CONTINUEUS : { BlockContinueus *block = (BlockContinueus *)(*i); for (int j = block->m_start; j <= block->m_end; j++) { FIBITMAP *dib = header->node->m_plugin->load_proc(header->io, header->handle, j, header->load_flags, data_read); success = header->node->m_plugin->save_proc(header->io, dib, (fi_handle)f, count, flags, data); count++; FreeImage_Unload(dib); } break; } case BLOCK_REFERENCE : { BlockReference *ref = (BlockReference *)(*i); // read the compressed data BYTE *compressed_data = (BYTE*)malloc(ref->m_size * sizeof(BYTE)); header->m_cachefile->readFile((BYTE *)compressed_data, ref->m_reference, ref->m_size); // uncompress the data FIMEMORY *hmem = FreeImage_OpenMemory(compressed_data, ref->m_size); FIBITMAP *dib = FreeImage_LoadFromMemory(header->cache_fif, hmem, 0); FreeImage_CloseMemory(hmem); // get rid of the buffer free(compressed_data); // save the data success = header->node->m_plugin->save_proc(header->io, dib, (fi_handle)f, count, flags, data); count++; // unload the dib FreeImage_Unload(dib); break; } } } else { break; } } // close the files FreeImage_Close(header->node, header->io, (fi_handle)f, data); fclose(f); if (header->handle) { FreeImage_Close(header->node, header->io, header->handle, data_read); fclose((FILE *)header->handle); } if (success) { remove(header->m_filename); rename(spool_name, header->m_filename); } else { remove(spool_name); } } else { if (header->handle) { fclose((FILE *)header->handle); } } // clear the blocks list for (BlockListIterator i = header->m_blocks.begin(); i != header->m_blocks.end(); ++i) delete *i; // flush and dispose the cache if (header->m_cachefile) { header->m_cachefile->close(); delete header->m_cachefile; } // delete the last open bitmaps while (!header->locked_pages.empty()) { FreeImage_Unload(header->locked_pages.begin()->first); header->locked_pages.erase(header->locked_pages.begin()->first); } // get rid of the IO structure delete header->io; // delete the filename delete[] header->m_filename; // delete the FIMULTIBITMAPHEADER delete header; } delete bitmap; return success; } return FALSE; }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { TIFF *faxTIFF = NULL; FIBITMAP *dib = NULL; FIMEMORY *memory = NULL; //int verbose = 0; int stretch = 0; int rows; float resX = 204.0; float resY = 196.0; uint32 xsize = G3_DEFAULT_WIDTH; int compression_in = COMPRESSION_CCITTFAX3; int fillorder_in = FILLORDER_LSB2MSB; uint32 group3options_in = 0; // 1d-encoded uint32 group4options_in = 0; // compressed int photometric_in = PHOTOMETRIC_MINISWHITE; if(handle==NULL) return NULL; try { // set default load options compression_in = COMPRESSION_CCITTFAX3; // input is g3-encoded group3options_in &= ~GROUP3OPT_2DENCODING; // input is 1d-encoded (g3 only) fillorder_in = FILLORDER_MSB2LSB; // input has msb-to-lsb fillorder /* Original input-related fax2tiff options while ((c = getopt(argc, argv, "R:X:o:1234ABLMPUW5678abcflmprsuvwz?")) != -1) { switch (c) { // input-related options case '3': // input is g3-encoded compression_in = COMPRESSION_CCITTFAX3; break; case '4': // input is g4-encoded compression_in = COMPRESSION_CCITTFAX4; break; case 'U': // input is uncompressed (g3 and g4) group3options_in |= GROUP3OPT_UNCOMPRESSED; group4options_in |= GROUP4OPT_UNCOMPRESSED; break; case '1': // input is 1d-encoded (g3 only) group3options_in &= ~GROUP3OPT_2DENCODING; break; case '2': // input is 2d-encoded (g3 only) group3options_in |= GROUP3OPT_2DENCODING; break; case 'P': // input has not-aligned EOL (g3 only) group3options_in &= ~GROUP3OPT_FILLBITS; break; case 'A': // input has aligned EOL (g3 only) group3options_in |= GROUP3OPT_FILLBITS; break; case 'W': // input has 0 mean white photometric_in = PHOTOMETRIC_MINISWHITE; break; case 'B': // input has 0 mean black photometric_in = PHOTOMETRIC_MINISBLACK; break; case 'L': // input has lsb-to-msb fillorder fillorder_in = FILLORDER_LSB2MSB; break; case 'M': // input has msb-to-lsb fillorder fillorder_in = FILLORDER_MSB2LSB; break; case 'R': // input resolution resY = (float) atof(optarg); break; case 'X': // input width xsize = (uint32) atoi(optarg); break; // output-related options case 's': // stretch image by dup'ng scanlines stretch = 1; break; case 'v': // -v for info verbose++; break; } } */ // open a temporary memory buffer to save decoded scanlines memory = FreeImage_OpenMemory(); if(!memory) throw FI_MSG_ERROR_MEMORY; // wrap the raw fax file faxTIFF = TIFFClientOpen("(FakeInput)", "w", // TIFFClientOpen() fails if we don't set existing value here NULL, _g3ReadProc, _g3WriteProc, _g3SeekProc, _g3CloseProc, _g3SizeProc, _g3MapProc, _g3UnmapProc); if (faxTIFF == NULL) { throw "Can not create fake input file"; } TIFFSetMode(faxTIFF, O_RDONLY); TIFFSetField(faxTIFF, TIFFTAG_IMAGEWIDTH, xsize); TIFFSetField(faxTIFF, TIFFTAG_SAMPLESPERPIXEL, 1); TIFFSetField(faxTIFF, TIFFTAG_BITSPERSAMPLE, 1); TIFFSetField(faxTIFF, TIFFTAG_FILLORDER, fillorder_in); TIFFSetField(faxTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(faxTIFF, TIFFTAG_PHOTOMETRIC, photometric_in); TIFFSetField(faxTIFF, TIFFTAG_YRESOLUTION, resY); TIFFSetField(faxTIFF, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH); // NB: this must be done after directory info is setup TIFFSetField(faxTIFF, TIFFTAG_COMPRESSION, compression_in); if (compression_in == COMPRESSION_CCITTFAX3) TIFFSetField(faxTIFF, TIFFTAG_GROUP3OPTIONS, group3options_in); else if (compression_in == COMPRESSION_CCITTFAX4) TIFFSetField(faxTIFF, TIFFTAG_GROUP4OPTIONS, group4options_in); resX = 204; if (!stretch) { TIFFGetField(faxTIFF, TIFFTAG_YRESOLUTION, &resY); } else { resY = 196; } // decode the raw fax data rows = copyFaxFile(io, handle, faxTIFF, xsize, stretch, memory); if(rows <= 0) throw "Error when decoding raw fax file : check the decoder options"; // allocate the output dib dib = FreeImage_Allocate(xsize, rows, 1); unsigned pitch = FreeImage_GetPitch(dib); uint32 linesize = TIFFhowmany8(xsize); // fill the bitmap structure ... // ... palette RGBQUAD *pal = FreeImage_GetPalette(dib); if(photometric_in == PHOTOMETRIC_MINISWHITE) { pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255; pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 0; } else { pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0; pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; } // ... resolution FreeImage_SetDotsPerMeterX(dib, (unsigned)(resX/0.0254000 + 0.5)); FreeImage_SetDotsPerMeterY(dib, (unsigned)(resY/0.0254000 + 0.5)); // read the decoded scanline and fill the bitmap data FreeImage_SeekMemory(memory, 0, SEEK_SET); BYTE *bits = FreeImage_GetScanLine(dib, rows - 1); for(int k = 0; k < rows; k++) { FreeImage_ReadMemory(bits, linesize, 1, memory); bits -= pitch; } // free the TIFF wrapper TIFFClose(faxTIFF); // free the memory buffer FreeImage_CloseMemory(memory); } catch(const char *message) { if(memory) FreeImage_CloseMemory(memory); if(faxTIFF) TIFFClose(faxTIFF); if(dib) FreeImage_Unload(dib); FreeImage_OutputMessageProc(s_format_id, message); return NULL; } return dib; }
FIBITMAP* loadVRH(const FileName& fileName) { HANDLE hFile = CreateFile(fileName.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE || hFile == NULL) { DWORD dwErr = GetLastError(); //std::cerr << "Input CreateFile failed. ErrorCode: " << dwErr << std::endl; return NULL; } DWORD dwFileSizeHigh = 0; DWORD dwFileSize = GetFileSize(hFile, &dwFileSizeHigh); if(dwFileSize == 0 && dwFileSizeHigh == 0) { //std::cerr << "Input file empty." << std::endl; CloseHandle(hFile); return NULL; } // Dateiinhalt aus Geschwindigkeitsgründen in den Prozessadressspeicher (process address space) mappen HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); if(hFileMap == INVALID_HANDLE_VALUE || hFileMap == NULL) { DWORD dwErr = GetLastError(); //std::cerr << "Input CreateFileMapping failed. ErrorCode: " << dwErr << std::endl; CloseHandle(hFileMap); CloseHandle(hFile); return NULL; } BYTE* pData = (BYTE*)MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0); if(pData == NULL) { DWORD dwErr = GetLastError(); //std::cerr << "Input MapViewOfFile failed. ErrorCode: " << dwErr << std::endl; CloseHandle(hFileMap); CloseHandle(hFile); return NULL; } unsigned char sig[4] = {0}; memcpy_s(sig, _countof(sig), pData, _countof(sig)); pData += _countof(sig); bool IsSignatureValid = (sig[0] == 'V' && sig[1] == 'R' && sig[2] == 'H' && sig[3] == 'Z'); if(!IsSignatureValid) { //std::cerr << "Invalid Signature." << std::endl; UnmapViewOfFile(pData); CloseHandle(hFileMap); CloseHandle(hFile); return NULL; } DWORD origSize = 0; memcpy_s(&origSize, sizeof(DWORD), pData, sizeof(DWORD)); pData += sizeof(DWORD); DWORD compSize = 0; memcpy_s(&compSize, sizeof(DWORD), pData, sizeof(DWORD)); pData += sizeof(DWORD); DWORD bufsize = origSize; BYTE* compdata = (BYTE*)malloc(bufsize * sizeof(BYTE)); z_stream strm = {0}; int ret = inflateInit(&strm); if(ret != Z_OK) { //std::cerr << "inflateInit returned " << ret << "." << std::endl; UnmapViewOfFile(pData); CloseHandle(hFileMap); CloseHandle(hFile); return NULL; } strm.avail_in = compSize; strm.next_in = pData; strm.avail_out = bufsize; strm.next_out = compdata; int ret2 = inflate(&strm, Z_FINISH); if(ret2 != Z_STREAM_END) { //std::cerr << "inflate returned " << ret2 << "." << std::endl; inflateEnd(&strm); UnmapViewOfFile(pData); CloseHandle(hFileMap); CloseHandle(hFile); return NULL; } int ret3 = inflateEnd(&strm); if(ret3 != Z_OK) { //std::cerr << "inflateEnd returned " << ret3 << "." << std::endl; UnmapViewOfFile(pData); CloseHandle(hFileMap); CloseHandle(hFile); return NULL; } DWORD inSize = strm.total_in; DWORD outSize = strm.total_out; if(inSize != compSize) { //std::cerr << "Input file size mismatch. (inSize != compSize)" << std::endl; UnmapViewOfFile(pData); CloseHandle(hFileMap); CloseHandle(hFile); return NULL; } if(outSize != origSize) { //std::cerr << "Output file size mismatch. (outSize != OrigSize)" << std::endl; UnmapViewOfFile(pData); CloseHandle(hFileMap); CloseHandle(hFile); return NULL; } UnmapViewOfFile(pData); pData = NULL; CloseHandle(hFileMap); CloseHandle(hFile); hFileMap = INVALID_HANDLE_VALUE; hFile = INVALID_HANDLE_VALUE; FIMEMORY* fiMem = FreeImage_OpenMemory(compdata, outSize); if(!fiMem) { return NULL; } FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeFromMemory(fiMem); FIBITMAP* fiDib = FreeImage_LoadFromMemory(fif, fiMem); FreeImage_CloseMemory(fiMem); return fiDib; }
//--------------------------------------------------------------------- Codec::DecodeResult FreeImageCodec::decode(DataStreamPtr& input) const { // Buffer stream into memory (TODO: override IO functions instead?) MemoryDataStream memStream(input, true); FIMEMORY* fiMem = FreeImage_OpenMemory(memStream.getPtr(), static_cast<DWORD>(memStream.size())); FIBITMAP* fiBitmap = FreeImage_LoadFromMemory( (FREE_IMAGE_FORMAT)mFreeImageType, fiMem); if (!fiBitmap) { OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Error decoding image", "FreeImageCodec::decode"); } ImageData* imgData = OGRE_NEW ImageData(); MemoryDataStreamPtr output; imgData->depth = 1; // only 2D formats handled by this codec imgData->width = FreeImage_GetWidth(fiBitmap); imgData->height = FreeImage_GetHeight(fiBitmap); imgData->num_mipmaps = 0; // no mipmaps in non-DDS imgData->flags = 0; // Must derive format first, this may perform conversions FREE_IMAGE_TYPE imageType = FreeImage_GetImageType(fiBitmap); FREE_IMAGE_COLOR_TYPE colourType = FreeImage_GetColorType(fiBitmap); unsigned bpp = FreeImage_GetBPP(fiBitmap); switch(imageType) { case FIT_UNKNOWN: case FIT_COMPLEX: case FIT_UINT32: case FIT_INT32: case FIT_DOUBLE: default: OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Unknown or unsupported image format", "FreeImageCodec::decode"); break; case FIT_BITMAP: // Standard image type // Perform any colour conversions for greyscale if (colourType == FIC_MINISWHITE || colourType == FIC_MINISBLACK) { FIBITMAP* newBitmap = FreeImage_ConvertToGreyscale(fiBitmap); // free old bitmap and replace FreeImage_Unload(fiBitmap); fiBitmap = newBitmap; // get new formats bpp = FreeImage_GetBPP(fiBitmap); colourType = FreeImage_GetColorType(fiBitmap); } // Perform any colour conversions for RGB else if (bpp < 8 || colourType == FIC_PALETTE || colourType == FIC_CMYK) { FIBITMAP* newBitmap = FreeImage_ConvertTo24Bits(fiBitmap); // free old bitmap and replace FreeImage_Unload(fiBitmap); fiBitmap = newBitmap; // get new formats bpp = FreeImage_GetBPP(fiBitmap); colourType = FreeImage_GetColorType(fiBitmap); } // by this stage, 8-bit is greyscale, 16/24/32 bit are RGB[A] switch(bpp) { case 8: imgData->format = PF_L8; break; case 16: // Determine 555 or 565 from green mask // cannot be 16-bit greyscale since that's FIT_UINT16 if(FreeImage_GetGreenMask(fiBitmap) == FI16_565_GREEN_MASK) { imgData->format = PF_R5G6B5; } else { // FreeImage doesn't support 4444 format so must be 1555 imgData->format = PF_A1R5G5B5; } break; case 24: // FreeImage differs per platform // PF_BYTE_BGR[A] for little endian (== PF_ARGB native) // PF_BYTE_RGB[A] for big endian (== PF_RGBA native) #if OGRE_ENDIAN == OGRE_ENDIAN_BIG imgData->format = PF_BYTE_RGB; #else imgData->format = PF_BYTE_BGR; #endif break; case 32: #if OGRE_ENDIAN == OGRE_ENDIAN_BIG imgData->format = PF_BYTE_RGBA; #else imgData->format = PF_BYTE_BGRA; #endif break; }; break; case FIT_UINT16: case FIT_INT16: // 16-bit greyscale imgData->format = PF_L16; break; case FIT_FLOAT: // Single-component floating point data imgData->format = PF_FLOAT32_R; break; case FIT_RGB16: imgData->format = PF_SHORT_RGB; break; case FIT_RGBA16: imgData->format = PF_SHORT_RGBA; break; case FIT_RGBF: imgData->format = PF_FLOAT32_RGB; break; case FIT_RGBAF: imgData->format = PF_FLOAT32_RGBA; break; }; unsigned char* srcData = FreeImage_GetBits(fiBitmap); unsigned srcPitch = FreeImage_GetPitch(fiBitmap); // Final data - invert image and trim pitch at the same time size_t dstPitch = imgData->width * PixelUtil::getNumElemBytes(imgData->format); imgData->size = dstPitch * imgData->height; // Bind output buffer output.bind(OGRE_NEW MemoryDataStream(imgData->size)); uchar* pSrc; uchar* pDst = output->getPtr(); for (size_t y = 0; y < imgData->height; ++y) { pSrc = srcData + (imgData->height - y - 1) * srcPitch; memcpy(pDst, pSrc, dstPitch); pDst += dstPitch; } FreeImage_Unload(fiBitmap); FreeImage_CloseMemory(fiMem); DecodeResult ret; ret.first = output; ret.second = CodecDataPtr(imgData); return ret; }
bool ofMemoryImage::loadFromDataIntoPixels(const unsigned char * datasource, int len, ofPixels &pix ) { int width, height, bpp; bool bLoaded = false; FIBITMAP * bmp = NULL; FIMEMORY *hmem = NULL; hmem = FreeImage_OpenMemory((Byte *)datasource, len); if (hmem == NULL) { printf("couldn't create memory handle! \n"); } cout << "memory open " << endl; //get the file type! FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeFromMemory(hmem); cout << "image format "<< fif << endl; if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) { bmp = FreeImage_LoadFromMemory(fif, hmem, 0); if (bmp == NULL) { cout << "we could not load from memory!! " << endl; } else { FreeImage_CloseMemory(hmem); } bLoaded = true; if (bmp == NULL) { bLoaded = false; cout << "we are not loadded " << endl; } } if (bLoaded ) { width = FreeImage_GetWidth(bmp); height = FreeImage_GetHeight(bmp); bpp = FreeImage_GetBPP(bmp); bool bPallette = (FreeImage_GetColorType(bmp) == FIC_PALETTE); switch (bpp) { case 8: if (bPallette) { FIBITMAP * bmpTemp = FreeImage_ConvertTo24Bits(bmp); if (bmp != NULL) FreeImage_Unload(bmp); bmp = bmpTemp; bpp = FreeImage_GetBPP(bmp); } else { // do nothing we are grayscale } break; case 24: // do nothing we are color break; case 32: // do nothing we are colorAlpha break; default: FIBITMAP * bmpTemp = FreeImage_ConvertTo24Bits(bmp); if (bmp != NULL) FreeImage_Unload(bmp); bmp = bmpTemp; bpp = FreeImage_GetBPP(bmp); } int byteCount = bpp / 8; //------------------------------------------ // call the allocation routine (which checks if really need to allocate) here: allocatePixels(pix, width, height, bpp); FreeImage_ConvertToRawBits(pix.pixels, bmp, width*byteCount, bpp, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, false); // get bits //------------------------------------------ // RGB or RGBA swap // this can be done with some ill pointer math. // anyone game? // #ifdef TARGET_LITTLE_ENDIAN if (byteCount != 1) swapRgb(pix); #endif //------------------------------------------ } else { width = height = bpp = 0; } if (bmp != NULL) { FreeImage_Unload(bmp); } cout << bLoaded << endl; return bLoaded; }
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; } }
std::vector<unsigned char> ImageIO::loadFromMemoryRGBA32(const unsigned char * data, const size_t size, size_t & width, size_t & height) { std::vector<unsigned char> rawData; width = 0; height = 0; FIMEMORY * fiMemory = FreeImage_OpenMemory((BYTE *)data, size); if (fiMemory != nullptr) { //detect the filetype from data FREE_IMAGE_FORMAT format = FreeImage_GetFileTypeFromMemory(fiMemory); if (format != FIF_UNKNOWN && FreeImage_FIFSupportsReading(format)) { //file type is supported. load image FIBITMAP * fiBitmap = FreeImage_LoadFromMemory(format, fiMemory); if (fiBitmap != nullptr) { //loaded. convert to 32bit if necessary FIBITMAP * fiConverted = nullptr; if (FreeImage_GetBPP(fiBitmap) != 32) { FIBITMAP * fiConverted = FreeImage_ConvertTo32Bits(fiBitmap); if (fiConverted != nullptr) { //free original bitmap data FreeImage_Unload(fiBitmap); fiBitmap = fiConverted; } } if (fiBitmap != nullptr) { width = FreeImage_GetWidth(fiBitmap); height = FreeImage_GetHeight(fiBitmap); unsigned int pitch = FreeImage_GetPitch(fiBitmap); //loop through scanlines and add all pixel data to the return vector //this is necessary, because width*height*bpp might not be == pitch unsigned char * tempData = new unsigned char[width * height * 4]; for (size_t i = 0; i < height; i++) { const BYTE * scanLine = FreeImage_GetScanLine(fiBitmap, i); memcpy(tempData + (i * width * 4), scanLine, width * 4); } //convert from BGRA to RGBA for(size_t i = 0; i < width*height; i++) { RGBQUAD bgra = ((RGBQUAD *)tempData)[i]; RGBQUAD rgba; rgba.rgbBlue = bgra.rgbRed; rgba.rgbGreen = bgra.rgbGreen; rgba.rgbRed = bgra.rgbBlue; rgba.rgbReserved = bgra.rgbReserved; ((RGBQUAD *)tempData)[i] = rgba; } rawData = std::vector<unsigned char>(tempData, tempData + width * height * 4); //free bitmap data FreeImage_Unload(fiBitmap); delete[] tempData; } } else { LOG(LogLevel::Error, "Error - Failed to load image from memory!"); } } else { LOG(LogLevel::Error, "Error - File type unknown/unsupported!"); } //free FIMEMORY again FreeImage_CloseMemory(fiMemory); } return rawData; }
fipMemoryIO::~fipMemoryIO() { if(_hmem != NULL) { FreeImage_CloseMemory(_hmem); } }
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; } if(format==OF_IMAGE_FORMAT_JPEG && pix.getNumChannels()==4){ ofPixels pix3 = pix; pix3.setNumChannels(3); saveImage(pix3,buffer,format,qualityLevel); 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); } }
void fipMemoryIO::close() { if(_hmem != NULL) { FreeImage_CloseMemory(_hmem); _hmem = NULL; } }
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 switch ((*i)->m_type) { case BLOCK_CONTINUEUS : { int iPage = header->m_cachefile->writeFile(compressed_data, compressed_size); delete (*i); *i = (BlockTypeS *)new BlockReference(iPage, compressed_size); break; } case BLOCK_REFERENCE : { BlockReference *reference = (BlockReference *)(*i); header->m_cachefile->deleteFile(reference->m_reference); delete (*i); int iPage = header->m_cachefile->writeFile(compressed_data, compressed_size); *i = (BlockTypeS *)new BlockReference(iPage, compressed_size); break; } } // 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); } } }
/** 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; } }