FIBITMAP *GraphicsHelps::loadImage(std::string file, bool convertTo32bit) { #ifdef DEBUG_BUILD ElapsedTimer loadingTime; ElapsedTimer fReadTime; ElapsedTimer imgConvTime; loadingTime.start(); fReadTime.start(); #endif #if defined(__unix__) || defined(__APPLE__) || defined(_WIN32) FileMapper fileMap; if(!fileMap.open_file(file.c_str())) return NULL; FIMEMORY *imgMEM = FreeImage_OpenMemory(reinterpret_cast<unsigned char *>(fileMap.data()), static_cast<unsigned int>(fileMap.size())); FREE_IMAGE_FORMAT formato = FreeImage_GetFileTypeFromMemory(imgMEM); if(formato == FIF_UNKNOWN) return NULL; FIBITMAP *img = FreeImage_LoadFromMemory(formato, imgMEM, 0); FreeImage_CloseMemory(imgMEM); fileMap.close_file(); if(!img) return NULL; #else FREE_IMAGE_FORMAT formato = FreeImage_GetFileType(file.toUtf8().data(), 0); if(formato == FIF_UNKNOWN) return NULL; FIBITMAP *img = FreeImage_Load(formato, file.toUtf8().data()); if(!img) return NULL; #endif #ifdef DEBUG_BUILD long long fReadTimeElapsed = static_cast<long long>(fReadTime.elapsed()); long long imgConvertElapsed = 0; #endif if(convertTo32bit) { #ifdef DEBUG_BUILD imgConvTime.start(); #endif FIBITMAP *temp; temp = FreeImage_ConvertTo32Bits(img); if(!temp) return NULL; FreeImage_Unload(img); img = temp; #ifdef DEBUG_BUILD imgConvertElapsed = static_cast<long long>(imgConvTime.elapsed()); #endif } #ifdef DEBUG_BUILD D_pLogDebug("File read of texture %s passed in %d milliseconds", file.c_str(), static_cast<int>(fReadTimeElapsed)); D_pLogDebug("Conv to 32-bit of %s passed in %d milliseconds", file.c_str(), static_cast<int>(imgConvertElapsed)); D_pLogDebug("Total Loading of image %s passed in %d milliseconds", file.c_str(), static_cast<int>(loadingTime.elapsed())); #endif return img; }
int liimg_png_load ( const char* file, int* result_width, int* result_height, void** result_pixels) { #ifdef HAVE_FREEIMAGE size_t i; size_t x; size_t y; size_t w; size_t h; uint8_t* pixels; FIBITMAP* image; RGBQUAD color; /* Load the image. */ image = FreeImage_Load (FIF_PNG, file, PNG_DEFAULT); if (image == NULL) return 0; /* Allocate pixel data. */ w = FreeImage_GetWidth (image); h = FreeImage_GetHeight (image); if (w > 0 && h > 0) { pixels = lisys_calloc (w * h * 4, 1); if (pixels == NULL) { FreeImage_Unload (image); return 0; } } else pixels = NULL; /* Copy the pixel data. */ for (y = 0, i = 0 ; y < h ; y++) { for (x = 0 ; x < w ; x++, i++) { FreeImage_GetPixelColor (image, x, h - y - 1, &color); pixels[4 * i + 0] = color.rgbRed; pixels[4 * i + 1] = color.rgbGreen; pixels[4 * i + 2] = color.rgbBlue; if (FreeImage_GetBPP (image) == 32) pixels[4 * i + 3] = color.rgbReserved; else pixels[4 * i + 3] = 0xFF; } } /* Set the results. */ *result_width = w; *result_height = h; *result_pixels = pixels; FreeImage_Unload (image); return 1; #else int x; int y; int depth; int width; int height; char* dst; void* pixels; FILE* fp; png_bytepp rows; png_infop info; png_structp png; /* Initialize structures. */ png = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png == NULL) { lisys_error_set (ENOMEM, NULL); return 0; } info = png_create_info_struct (png); if (info == NULL) { png_destroy_read_struct (&png, NULL, NULL); lisys_error_set (ENOMEM, NULL); return 0; } /* Open file. */ fp = fopen (file, "rb"); if (fp == NULL) { lisys_error_set (EIO, "cannot open file `%s'", file); png_destroy_read_struct (&png, &info, NULL); return 0; } /* Read data. */ if (setjmp (png_jmpbuf (png))) { lisys_error_set (EIO, "error while reading `%s'", file); png_destroy_read_struct (&png, &info, NULL); fclose (fp); return 0; } png_init_io (png, fp); png_read_png (png, info, PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING, NULL); width = png_get_image_width (png, info); height = png_get_image_height (png, info); rows = png_get_rows (png, info); depth = png_get_rowbytes (png, info); depth /= width; fclose (fp); /* Allocate pixel data. */ pixels = lisys_malloc (width * height * 4); if (pixels == NULL) { png_destroy_read_struct (&png, &info, NULL); return 0; } /* Copy pixel data. */ if (depth == 3) { for (y = 0 ; y < height ; y++) { dst = pixels + 4 * width * y; for (x = 0 ; x < width ; x++) { dst[4 * x + 0] = ((char*) rows[y])[3 * x + 0]; dst[4 * x + 1] = ((char*) rows[y])[3 * x + 1]; dst[4 * x + 2] = ((char*) rows[y])[3 * x + 2]; dst[4 * x + 3] = 0xFF; } } } else { for (y = 0 ; y < height ; y++) { dst = pixels + 4 * width * y; memcpy (dst, rows[y], 4 * width); } } *result_pixels = pixels; *result_width = width; *result_height = height; png_destroy_read_struct (&png, &info, NULL); return 1; #endif }
bool Texture::saveImToFile(const std::string& filename, const uint8_t* im, const uint32_t width, const uint32_t height, const bool save_flipped, const uint32_t num_channels) { freeimage_init_lock_.lock(); if (!freeimage_init_) { freeimage_init_lock_.unlock(); throw std::wruntime_error("Texture::Texture() - ERROR: Please call " "initTextureSystem() before loading textures from file!"); } freeimage_init_lock_.unlock(); // NEW CODE USING THE FREEIMAGE LIBRARY FREE_IMAGE_FORMAT fif = FIF_UNKNOWN; //image format // if still unknown, try to guess the file format from the file extension if (fif == FIF_UNKNOWN) { fif = FreeImage_GetFIFFromFilename(filename.c_str()); } // if still unkown, return failure if (fif == FIF_UNKNOWN) { throw wruntime_error(wstring(L"saveRGBToFile() - ERROR: Cannot deduce " L"format of the filename: ") + string_util::ToWideString(filename)); } if (!FreeImage_FIFSupportsWriting(fif)) { throw std::wruntime_error("saveRGBToFile() - ERROR: Freeimage does not " "support writing to this image format!"); return false; } BYTE* fi_bits = NULL; uint8_t* im_rev = NULL; // Unfortunately, Freeimage has a bug: // http://sourceforge.net/p/freeimage/bugs/172/ // It ignores the mask properties and so the red and blue channels (24bpp) // get flipped. Unfortunately, we have to swap them around. // As of 4/26/2013 this issue still isn't fixed. switch (num_channels) { case 0: throw std::wruntime_error("saveImToFile() - ERROR: num_channels == 0"); case 1: fi_bits = (BYTE*)im; break; case 2: case 3: im_rev = new uint8_t[width * height * num_channels]; for (uint32_t i = 0; i < width * height * num_channels; i+=num_channels) { for (uint32_t j = 0; j < num_channels; j++) { im_rev[i + j] = im[i + (num_channels - 1 - j)]; } } fi_bits = (BYTE*)im_rev; break; default: throw std::wruntime_error("saveImToFile() - ERROR: num_channels > 0." " Saving images with alpha not yet supported."); } uint32_t pitch = num_channels * width; uint32_t bpp = 8 * num_channels; uint32_t red_mask = 0x0000FF; // Free image likes the mask backwards? uint32_t green_mask = 0x00FF00; uint32_t blue_mask = 0xFF0000; FIBITMAP* fi_bit_map = FreeImage_ConvertFromRawBits(fi_bits, width, height, pitch, bpp, red_mask, blue_mask, green_mask, save_flipped); bool ret = false; if (fi_bit_map) { ret = (bool)FreeImage_Save(fif, fi_bit_map, filename.c_str(), JPEG_QUALITYSUPERB); } if (fi_bit_map) { FreeImage_Unload(fi_bit_map); } SAFE_DELETE_ARR(im_rev); return ret; }
/** Compute gradients in x and y directions, attenuate them with the attenuation matrix, then compute the divergence div G from the attenuated gradient. @param H Normalized luminance @param PHI Attenuation matrix @return Returns the divergence matrix if successful, returns NULL otherwise */ static FIBITMAP* Divergence(FIBITMAP *H, FIBITMAP *PHI) { FIBITMAP *Gx = NULL, *Gy = NULL, *divG = NULL; float *phi, *h, *gx, *gy, *divg; try { const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(H); if(image_type != FIT_FLOAT) throw(1); const unsigned width = FreeImage_GetWidth(H); const unsigned height = FreeImage_GetHeight(H); Gx = FreeImage_AllocateT(image_type, width, height); if(!Gx) throw(1); Gy = FreeImage_AllocateT(image_type, width, height); if(!Gy) throw(1); const unsigned pitch = FreeImage_GetPitch(H) / sizeof(float); // perform gradient attenuation phi = (float*)FreeImage_GetBits(PHI); h = (float*)FreeImage_GetBits(H); gx = (float*)FreeImage_GetBits(Gx); gy = (float*)FreeImage_GetBits(Gy); for(unsigned y = 0; y < height; y++) { const unsigned s = (y+1 == height ? y : y+1); for(unsigned x = 0; x < width; x++) { const unsigned e = (x+1 == width ? x : x+1); // forward difference const unsigned index = y*pitch + x; const float phi_xy = phi[index]; const float h_xy = h[index]; gx[x] = (h[y*pitch+e] - h_xy) * phi_xy; // [H(x+1, y) - H(x, y)] * PHI(x, y) gy[x] = (h[s*pitch+x] - h_xy) * phi_xy; // [H(x, y+1) - H(x, y)] * PHI(x, y) } // next line gx += pitch; gy += pitch; } // calculate the divergence divG = FreeImage_AllocateT(image_type, width, height); if(!divG) throw(1); gx = (float*)FreeImage_GetBits(Gx); gy = (float*)FreeImage_GetBits(Gy); divg = (float*)FreeImage_GetBits(divG); for(unsigned y0 = 0; y0 < height; y0++) { for(unsigned x = 0; x < width; x++) { // backward difference approximation // divG = Gx(x, y) - Gx(x-1, y) + Gy(x, y) - Gy(x, y-1) const unsigned index = y0*pitch + x; divg[index] = gx[index] + gy[index]; if(x > 0) divg[index] -= gx[index-1]; if(y0 > 0) divg[index] -= gy[index-pitch]; } } // no longer needed ... FreeImage_Unload(Gx); FreeImage_Unload(Gy); // return the divergence return divG; } catch(int) { if(Gx) FreeImage_Unload(Gx); if(Gy) FreeImage_Unload(Gy); if(divG) FreeImage_Unload(divG); return NULL; } }
/** Gradient Domain HDR tone mapping operator @param Y Image luminance values @param alpha Parameter alpha of the paper (suggested value is 0.1) @param beta Parameter beta of the paper (suggested value is between 0.8 and 0.9) @return returns the tone mapped luminance */ static FIBITMAP* tmoFattal02(FIBITMAP *Y, float alpha, float beta) { const unsigned MIN_PYRAMID_SIZE = 32; // minimun size (width or height) of the coarsest level of the pyramid FIBITMAP *H = NULL; FIBITMAP **pyramid = NULL; FIBITMAP **gradients = NULL; FIBITMAP *phy = NULL; FIBITMAP *divG = NULL; FIBITMAP *U = NULL; float *avgGrad = NULL; int k; int nlevels = 0; try { // get the normalized luminance FIBITMAP *H = LogLuminance(Y); if(!H) throw(1); // get the number of levels for the pyramid const unsigned width = FreeImage_GetWidth(H); const unsigned height = FreeImage_GetHeight(H); unsigned minsize = MIN(width, height); while(minsize >= MIN_PYRAMID_SIZE) { nlevels++; minsize /= 2; } // create the Gaussian pyramid pyramid = (FIBITMAP**)malloc(nlevels * sizeof(FIBITMAP*)); if(!pyramid) throw(1); memset(pyramid, 0, nlevels * sizeof(FIBITMAP*)); if(!GaussianPyramid(H, pyramid, nlevels)) throw(1); // calculate gradient magnitude and its average value on each pyramid level gradients = (FIBITMAP**)malloc(nlevels * sizeof(FIBITMAP*)); if(!gradients) throw(1); memset(gradients, 0, nlevels * sizeof(FIBITMAP*)); avgGrad = (float*)malloc(nlevels * sizeof(float)); if(!avgGrad) throw(1); if(!GradientPyramid(pyramid, nlevels, gradients, avgGrad)) throw(1); // free the Gaussian pyramid for(k = 0; k < nlevels; k++) { if(pyramid[k]) FreeImage_Unload(pyramid[k]); } free(pyramid); pyramid = NULL; // compute the gradient attenuation function PHI(x, y) phy = PhiMatrix(gradients, avgGrad, nlevels, alpha, beta); if(!phy) throw(1); // free the gradient pyramid for(k = 0; k < nlevels; k++) { if(gradients[k]) FreeImage_Unload(gradients[k]); } free(gradients); gradients = NULL; free(avgGrad); avgGrad = NULL; // compute gradients in x and y directions, attenuate them with the attenuation matrix, // then compute the divergence div G from the attenuated gradient. divG = Divergence(H, phy); if(!divG) throw(1); // H & phy no longer needed FreeImage_Unload(H); H = NULL; FreeImage_Unload(phy); phy = NULL; // solve the PDE (Poisson equation) using a multigrid solver and 3 cycles FIBITMAP *U = FreeImage_MultigridPoissonSolver(divG, 3); if(!U) throw(1); FreeImage_Unload(divG); // perform exponentiation and recover the log compressed image ExpLuminance(U); return U; } catch(int) { if(H) FreeImage_Unload(H); if(pyramid) { for(int i = 0; i < nlevels; i++) { if(pyramid[i]) FreeImage_Unload(pyramid[i]); } free(pyramid); } if(gradients) { for(int i = 0; i < nlevels; i++) { if(gradients[i]) FreeImage_Unload(gradients[i]); } free(gradients); } if(avgGrad) free(avgGrad); if(phy) FreeImage_Unload(phy); if(divG) FreeImage_Unload(divG); if(U) FreeImage_Unload(U); return NULL; } }
psdThumbnail::~psdThumbnail() { FreeImage_Unload(_dib); }
FIBITMAP* psdParser::ReadImageData(FreeImageIO *io, fi_handle handle) { if(handle == NULL) return NULL; bool header_only = (_fi_flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; WORD nCompression = 0; io->read_proc(&nCompression, sizeof(nCompression), 1, handle); #ifndef FREEIMAGE_BIGENDIAN SwapShort(&nCompression); #endif if((nCompression != PSDP_COMPRESSION_NONE && nCompression != PSDP_COMPRESSION_RLE)) { FreeImage_OutputMessageProc(_fi_format_id, "Unsupported compression %d", nCompression); return NULL; } const unsigned nWidth = _headerInfo._Width; const unsigned nHeight = _headerInfo._Height; const unsigned nChannels = _headerInfo._Channels; const unsigned depth = _headerInfo._BitsPerChannel; const unsigned bytes = (depth == 1) ? 1 : depth / 8; // channel(plane) line (BYTE aligned) const unsigned lineSize = (_headerInfo._BitsPerChannel == 1) ? (nWidth + 7) / 8 : nWidth * bytes; if(nCompression == PSDP_COMPRESSION_RLE && depth > 16) { FreeImage_OutputMessageProc(_fi_format_id, "Unsupported RLE with depth %d", depth); return NULL; } // build output buffer FIBITMAP* bitmap = NULL; unsigned dstCh = 0; short mode = _headerInfo._ColourMode; if(mode == PSDP_MULTICHANNEL && nChannels < 3) { // CM mode = PSDP_GRAYSCALE; // C as gray, M as extra channel } bool needPalette = false; switch (mode) { case PSDP_BITMAP: case PSDP_DUOTONE: case PSDP_INDEXED: case PSDP_GRAYSCALE: dstCh = 1; switch(depth) { case 16: bitmap = FreeImage_AllocateHeaderT(header_only, FIT_UINT16, nWidth, nHeight, depth*dstCh); break; case 32: bitmap = FreeImage_AllocateHeaderT(header_only, FIT_FLOAT, nWidth, nHeight, depth*dstCh); break; default: // 1-, 8- needPalette = true; bitmap = FreeImage_AllocateHeader(header_only, nWidth, nHeight, depth*dstCh); break; } break; case PSDP_RGB: case PSDP_LAB: case PSDP_CMYK : case PSDP_MULTICHANNEL : // force PSDP_MULTICHANNEL CMY as CMYK dstCh = (mode == PSDP_MULTICHANNEL && !header_only) ? 4 : MIN<unsigned>(nChannels, 4); if(dstCh < 3) { throw "Invalid number of channels"; } switch(depth) { case 16: bitmap = FreeImage_AllocateHeaderT(header_only, dstCh < 4 ? FIT_RGB16 : FIT_RGBA16, nWidth, nHeight, depth*dstCh); break; case 32: bitmap = FreeImage_AllocateHeaderT(header_only, dstCh < 4 ? FIT_RGBF : FIT_RGBAF, nWidth, nHeight, depth*dstCh); break; default: bitmap = FreeImage_AllocateHeader(header_only, nWidth, nHeight, depth*dstCh); break; } break; default: throw "Unsupported color mode"; break; } if(!bitmap) { throw FI_MSG_ERROR_DIB_MEMORY; } // write thumbnail FreeImage_SetThumbnail(bitmap, _thumbnail.getDib()); // @todo Add some metadata model if(header_only) { return bitmap; } // Load pixels data const unsigned dstChannels = dstCh; const unsigned dstBpp = (depth == 1) ? 1 : FreeImage_GetBPP(bitmap)/8; const unsigned dstLineSize = FreeImage_GetPitch(bitmap); BYTE* const dst_first_line = FreeImage_GetScanLine(bitmap, nHeight - 1);//<*** flipped BYTE* line_start = new BYTE[lineSize]; //< fileline cache switch ( nCompression ) { case PSDP_COMPRESSION_NONE: // raw data { for(unsigned c = 0; c < nChannels; c++) { if(c >= dstChannels) { // @todo write extra channels break; } const unsigned channelOffset = c * bytes; BYTE* dst_line_start = dst_first_line; for(unsigned h = 0; h < nHeight; ++h, dst_line_start -= dstLineSize) {//<*** flipped io->read_proc(line_start, lineSize, 1, handle); for (BYTE *line = line_start, *dst_line = dst_line_start; line < line_start + lineSize; line += bytes, dst_line += dstBpp) { #ifdef FREEIMAGE_BIGENDIAN memcpy(dst_line + channelOffset, line, bytes); #else // reverse copy bytes for (unsigned b = 0; b < bytes; ++b) { dst_line[channelOffset + b] = line[(bytes-1) - b]; } #endif // FREEIMAGE_BIGENDIAN } } //< h }//< ch SAFE_DELETE_ARRAY(line_start); } break; case PSDP_COMPRESSION_RLE: // RLE compression { // The RLE-compressed data is preceeded by a 2-byte line size for each row in the data, // store an array of these // later use this array as WORD rleLineSizeList[nChannels][nHeight]; WORD *rleLineSizeList = new (std::nothrow) WORD[nChannels*nHeight]; if(!rleLineSizeList) { FreeImage_Unload(bitmap); SAFE_DELETE_ARRAY(line_start); throw std::bad_alloc(); } io->read_proc(rleLineSizeList, 2, nChannels * nHeight, handle); WORD largestRLELine = 0; for(unsigned ch = 0; ch < nChannels; ++ch) { for(unsigned h = 0; h < nHeight; ++h) { const unsigned index = ch * nHeight + h; #ifndef FREEIMAGE_BIGENDIAN SwapShort(&rleLineSizeList[index]); #endif if(largestRLELine < rleLineSizeList[index]) { largestRLELine = rleLineSizeList[index]; } } } BYTE* rle_line_start = new (std::nothrow) BYTE[largestRLELine]; if(!rle_line_start) { FreeImage_Unload(bitmap); SAFE_DELETE_ARRAY(line_start); SAFE_DELETE_ARRAY(rleLineSizeList); throw std::bad_alloc(); } // Read the RLE data (assume 8-bit) const BYTE* const line_end = line_start + lineSize; for (unsigned ch = 0; ch < nChannels; ch++) { const unsigned channelOffset = ch * bytes; BYTE* dst_line_start = dst_first_line; for(unsigned h = 0; h < nHeight; ++h, dst_line_start -= dstLineSize) {//<*** flipped const unsigned index = ch * nHeight + h; // - read and uncompress line - const WORD rleLineSize = rleLineSizeList[index]; io->read_proc(rle_line_start, rleLineSize, 1, handle); for (BYTE* rle_line = rle_line_start, *line = line_start; rle_line < rle_line_start + rleLineSize, line < line_end;) { int len = *rle_line++; // NOTE len is signed byte in PackBits RLE if ( len < 128 ) { //<- MSB is not set // uncompressed packet // (len + 1) bytes of data are copied ++len; // assert we don't write beyound eol memcpy(line, rle_line, line + len > line_end ? line_end - line : len); line += len; rle_line += len; } else if ( len > 128 ) { //< MSB is set // RLE compressed packet // One byte of data is repeated (–len + 1) times len ^= 0xFF; // same as (-len + 1) & 0xFF len += 2; // // assert we don't write beyound eol memset(line, *rle_line++, line + len > line_end ? line_end - line : len); line += len; } else if ( 128 == len ) { // Do nothing } }//< rle_line // - write line to destination - if(ch >= dstChannels) { // @todo write to extra channels break; } // byte by byte copy a single channel to pixel for (BYTE *line = line_start, *dst_line = dst_line_start; line < line_start + lineSize; line += bytes, dst_line += dstBpp) { #ifdef FREEIMAGE_BIGENDIAN memcpy(dst_line + channelOffset, line, bytes); #else // reverse copy bytes for (unsigned b = 0; b < bytes; ++b) { dst_line[channelOffset + b] = line[(bytes-1) - b]; } #endif // FREEIMAGE_BIGENDIAN } }//< h }//< ch SAFE_DELETE_ARRAY(line_start); SAFE_DELETE_ARRAY(rleLineSizeList); SAFE_DELETE_ARRAY(rle_line_start); } break; case 2: // ZIP without prediction, no specification break; case 3: // ZIP with prediction, no specification break; default: // Unknown format break; } // --- Further process the bitmap --- if((mode == PSDP_CMYK || mode == PSDP_MULTICHANNEL)) { // CMYK values are "inverted", invert them back if(mode == PSDP_MULTICHANNEL) { invertColor(bitmap); } else { FreeImage_Invert(bitmap); } if((_fi_flags & PSD_CMYK) == PSD_CMYK) { // keep as CMYK if(mode == PSDP_MULTICHANNEL) { //### we force CMY to be CMYK, but CMY has no ICC. // Create empty profile and add the flag. FreeImage_CreateICCProfile(bitmap, NULL, 0); FreeImage_GetICCProfile(bitmap)->flags |= FIICC_COLOR_IS_CMYK; } } else { // convert to RGB ConvertCMYKtoRGBA(bitmap); // The ICC Profile is no longer valid _iccProfile.clear(); // remove the pending A if not present in source if(nChannels == 4 || nChannels == 3 ) { FIBITMAP* t = RemoveAlphaChannel(bitmap); if(t) { FreeImage_Unload(bitmap); bitmap = t; } // else: silently fail } } } else if ( mode == PSDP_LAB && !((_fi_flags & PSD_LAB) == PSD_LAB)) { ConvertLABtoRGB(bitmap); } else { if (needPalette && FreeImage_GetPalette(bitmap)) { if(mode == PSDP_BITMAP) { CREATE_GREYSCALE_PALETTE_REVERSE(FreeImage_GetPalette(bitmap), 2); } else if(mode == PSDP_INDEXED) { if(!_colourModeData._plColourData || _colourModeData._Length != 768 || _ColourCount < 0) { FreeImage_OutputMessageProc(_fi_format_id, "Indexed image has no palette. Using the default grayscale one."); } else { _colourModeData.FillPalette(bitmap); } } // GRAYSCALE, DUOTONE - use default grayscale palette } #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR if(FreeImage_GetImageType(bitmap) == FIT_BITMAP) { SwapRedBlue32(bitmap); } #endif } return bitmap; }
FIBITMAP * DLL_CALLCONV FreeImage_ConvertToRGBF(FIBITMAP *dib) { FIBITMAP *src = NULL; FIBITMAP *dst = NULL; if(!FreeImage_HasPixels(dib)) return NULL; const FREE_IMAGE_TYPE src_type = FreeImage_GetImageType(dib); // check for allowed conversions switch(src_type) { case FIT_BITMAP: { // allow conversion from 24- and 32-bit const FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib); if((color_type != FIC_RGB) && (color_type != FIC_RGBALPHA)) { src = FreeImage_ConvertTo24Bits(dib); if(!src) return NULL; } else { src = dib; } break; } case FIT_UINT16: // allow conversion from 16-bit src = dib; break; case FIT_RGB16: // allow conversion from 48-bit RGB src = dib; break; case FIT_RGBA16: // allow conversion from 64-bit RGBA (ignore the alpha channel) src = dib; break; case FIT_FLOAT: // allow conversion from 32-bit float src = dib; break; case FIT_RGBAF: // allow conversion from 128-bit RGBAF src = dib; break; case FIT_RGBF: // RGBF type : clone the src return FreeImage_Clone(dib); break; default: return NULL; } // allocate dst image const unsigned width = FreeImage_GetWidth(src); const unsigned height = FreeImage_GetHeight(src); dst = FreeImage_AllocateT(FIT_RGBF, width, height); if(!dst) { if(src != dib) { FreeImage_Unload(src); } return NULL; } // copy metadata from src to dst FreeImage_CloneMetadata(dst, src); // convert from src type to RGBF const unsigned src_pitch = FreeImage_GetPitch(src); const unsigned dst_pitch = FreeImage_GetPitch(dst); switch(src_type) { case FIT_BITMAP: { // calculate the number of bytes per pixel (3 for 24-bit or 4 for 32-bit) const unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src); const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); for(unsigned y = 0; y < height; y++) { const BYTE *src_pixel = (BYTE*)src_bits; FIRGBF *dst_pixel = (FIRGBF*)dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] dst_pixel->red = (float)(src_pixel[FI_RGBA_RED]) / 255.0F; dst_pixel->green = (float)(src_pixel[FI_RGBA_GREEN]) / 255.0F; dst_pixel->blue = (float)(src_pixel[FI_RGBA_BLUE]) / 255.0F; src_pixel += bytespp; dst_pixel ++; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_UINT16: { const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); for(unsigned y = 0; y < height; y++) { const WORD *src_pixel = (WORD*)src_bits; FIRGBF *dst_pixel = (FIRGBF*)dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] const float dst_value = (float)src_pixel[x] / 65535.0F; dst_pixel[x].red = dst_value; dst_pixel[x].green = dst_value; dst_pixel[x].blue = dst_value; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_RGB16: { const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); for(unsigned y = 0; y < height; y++) { const FIRGB16 *src_pixel = (FIRGB16*) src_bits; FIRGBF *dst_pixel = (FIRGBF*) dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] dst_pixel[x].red = (float)(src_pixel[x].red) / 65535.0F; dst_pixel[x].green = (float)(src_pixel[x].green) / 65535.0F; dst_pixel[x].blue = (float)(src_pixel[x].blue) / 65535.0F; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_RGBA16: { const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); for(unsigned y = 0; y < height; y++) { const FIRGBA16 *src_pixel = (FIRGBA16*) src_bits; FIRGBF *dst_pixel = (FIRGBF*) dst_bits; for(unsigned x = 0; x < width; x++) { // convert and scale to the range [0..1] dst_pixel[x].red = (float)(src_pixel[x].red) / 65535.0F; dst_pixel[x].green = (float)(src_pixel[x].green) / 65535.0F; dst_pixel[x].blue = (float)(src_pixel[x].blue) / 65535.0F; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_FLOAT: { const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); for(unsigned y = 0; y < height; y++) { const float *src_pixel = (float*) src_bits; FIRGBF *dst_pixel = (FIRGBF*) dst_bits; for(unsigned x = 0; x < width; x++) { // convert by copying greyscale channel to each R, G, B channels // assume float values are in [0..1] const float value = CLAMP(src_pixel[x], 0.0F, 1.0F); dst_pixel[x].red = value; dst_pixel[x].green = value; dst_pixel[x].blue = value; } src_bits += src_pitch; dst_bits += dst_pitch; } } break; case FIT_RGBAF: { const BYTE *src_bits = (BYTE*)FreeImage_GetBits(src); BYTE *dst_bits = (BYTE*)FreeImage_GetBits(dst); for(unsigned y = 0; y < height; y++) { const FIRGBAF *src_pixel = (FIRGBAF*) src_bits; FIRGBF *dst_pixel = (FIRGBF*) dst_bits; for(unsigned x = 0; x < width; x++) { // convert and skip alpha channel dst_pixel[x].red = CLAMP(src_pixel[x].red, 0.0F, 1.0F); dst_pixel[x].green = CLAMP(src_pixel[x].green, 0.0F, 1.0F); dst_pixel[x].blue = CLAMP(src_pixel[x].blue, 0.0F, 1.0F); } src_bits += src_pitch; dst_bits += dst_pitch; } } break; } if(src != dib) { FreeImage_Unload(src); } return dst; }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { FIBITMAP *dib = NULL; LibRaw RawProcessor; BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; try { // wrap the input datastream LibRaw_freeimage_datastream datastream(io, handle); // open the datastream if(RawProcessor.open_datastream(&datastream) != LIBRAW_SUCCESS) { throw "LibRaw : failed to open input stream (unknown format)"; } if(header_only) { // header only mode dib = FreeImage_AllocateHeaderT(header_only, FIT_RGB16, RawProcessor.imgdata.sizes.width, RawProcessor.imgdata.sizes.height); // try to get JPEG embedded Exif metadata if(dib) { FIBITMAP *metadata_dib = libraw_LoadEmbeddedPreview(RawProcessor, FIF_LOAD_NOPIXELS); if(metadata_dib) { FreeImage_CloneMetadata(dib, metadata_dib); FreeImage_Unload(metadata_dib); } } } else if((flags & RAW_PREVIEW) == RAW_PREVIEW) { // try to get the embedded JPEG dib = libraw_LoadEmbeddedPreview(RawProcessor, 0); if(!dib) { // no JPEG preview: try to load as 8-bit/sample (i.e. RGB 24-bit) dib = libraw_LoadRawData(RawProcessor, 8); } } else if((flags & RAW_DISPLAY) == RAW_DISPLAY) { // load raw data as 8-bit/sample (i.e. RGB 24-bit) dib = libraw_LoadRawData(RawProcessor, 8); } else { // default: load raw data as linear 16-bit/sample (i.e. RGB 48-bit) dib = libraw_LoadRawData(RawProcessor, 16); } // save ICC profile if present if(NULL != RawProcessor.imgdata.color.profile) { FreeImage_CreateICCProfile(dib, RawProcessor.imgdata.color.profile, RawProcessor.imgdata.color.profile_length); } // try to get JPEG embedded Exif metadata if(dib && !((flags & RAW_PREVIEW) == RAW_PREVIEW) ) { FIBITMAP *metadata_dib = libraw_LoadEmbeddedPreview(RawProcessor, FIF_LOAD_NOPIXELS); if(metadata_dib) { FreeImage_CloneMetadata(dib, metadata_dib); FreeImage_Unload(metadata_dib); } } // clean-up internal memory allocations RawProcessor.recycle(); return dib; } catch(const char *text) { if(dib) { FreeImage_Unload(dib); } RawProcessor.recycle(); FreeImage_OutputMessageProc(s_format_id, text); } return NULL; }
static void saveImage(ofPixels_<PixelType> & pix, string fileName, ofImageQualityType qualityLevel) { ofInitFreeImage(); if (pix.isAllocated() == false){ ofLog(OF_LOG_ERROR,"error saving image - pixels aren't allocated"); return; } #ifdef TARGET_LITTLE_ENDIAN if(sizeof(PixelType) == 1) { pix.swapRgb(); } #endif FIBITMAP * bmp = getBmpFromPixels(pix); #ifdef TARGET_LITTLE_ENDIAN if(sizeof(PixelType) == 1) { pix.swapRgb(); } #endif fileName = ofToDataPath(fileName); FREE_IMAGE_FORMAT fif = FIF_UNKNOWN; fif = FreeImage_GetFileType(fileName.c_str(), 0); if(fif == FIF_UNKNOWN) { // or guess via filename fif = FreeImage_GetFIFFromFilename(fileName.c_str()); } if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) { if(fif == 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_Save(fif, bmp, fileName.c_str(), quality); } else { if(qualityLevel != OF_IMAGE_QUALITY_BEST) { ofLogWarning() << "ofImageCompressionType only applies to JPEG images, ignoring value"; } if (fif == FIF_GIF) { FIBITMAP* convertedBmp; if(pix.getImageType() == OF_IMAGE_COLOR_ALPHA) { // this just converts the image to grayscale so it can save something convertedBmp = FreeImage_ConvertTo8Bits(bmp); } else { // this will create a 256-color palette from the image convertedBmp = FreeImage_ColorQuantize(bmp, FIQ_NNQUANT); } FreeImage_Save(fif, convertedBmp, fileName.c_str()); if (convertedBmp != NULL){ FreeImage_Unload(convertedBmp); } } else { FreeImage_Save(fif, bmp, fileName.c_str()); } } } if (bmp != NULL){ FreeImage_Unload(bmp); } }
static void saveImage(ofPixels_<PixelType> & pix, ofBuffer & buffer, ofImageFormat format, ofImageQualityType qualityLevel) { //thanks to alvaro casinelli for the implementation ofInitFreeImage(); if (pix.isAllocated() == false){ ofLog(OF_LOG_ERROR,"error saving image - pixels aren't allocated"); return; } #ifdef TARGET_LITTLE_ENDIAN if(sizeof(PixelType) == 1) { pix.swapRgb(); } #endif FIBITMAP * bmp = getBmpFromPixels(pix); #ifdef TARGET_LITTLE_ENDIAN if(sizeof(PixelType) == 1) { pix.swapRgb(); } #endif if (bmp) // bitmap successfully created { // (b) open a memory stream to compress the image onto mem_buffer: // FIMEMORY *hmem = FreeImage_OpenMemory(); // (c) encode and save the image to the memory (on dib FIBITMAP image): // if(FREE_IMAGE_FORMAT(format) == FIF_JPEG) { int quality = JPEG_QUALITYSUPERB; switch(qualityLevel) { case OF_IMAGE_QUALITY_WORST: quality = JPEG_QUALITYBAD; break; case OF_IMAGE_QUALITY_LOW: quality = JPEG_QUALITYAVERAGE; break; case OF_IMAGE_QUALITY_MEDIUM: quality = JPEG_QUALITYNORMAL; break; case OF_IMAGE_QUALITY_HIGH: quality = JPEG_QUALITYGOOD; break; case OF_IMAGE_QUALITY_BEST: quality = JPEG_QUALITYSUPERB; break; } FreeImage_SaveToMemory(FIF_JPEG, bmp, hmem, quality); }else{ FreeImage_SaveToMemory((FREE_IMAGE_FORMAT)format, bmp, hmem); } /* NOTE: at this point, hmem contains the entire data in memory stored in fif format. the amount of space used by the memory is equal to file_size: long file_size = FreeImage_TellMemory(hmem); but can also be retrieved by FreeImage_AcquireMemory that retrieves both the length of the buffer, and the buffer memory address. */ #ifdef TARGET_WIN32 DWORD size_in_bytes = 0; #else uint32_t size_in_bytes = 0; #endif // Save compressed data on mem_buffer // note: FreeImage_AquireMemory allocates space for aux_mem_buffer): // unsigned char *mem_buffer = NULL; if (!FreeImage_AcquireMemory(hmem, &mem_buffer, &size_in_bytes)) cout << "Error aquiring compressed image from memory" << endl; /* Now, before closing the memory stream, copy the content of mem_buffer to an auxiliary buffer */ buffer.set((char*)mem_buffer,size_in_bytes); // Finally, close the FIBITMAP object, or we will get a memory leak: FreeImage_Unload(bmp); // Close the memory stream (otherwise we may get a memory leak). FreeImage_CloseMemory(hmem); } }
unsigned int LoadTexture(const char* a_szTexture) { FIBITMAP* pBitmap = nullptr; // Determime File Type from File Signature FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(a_szTexture, 0); // Success if (fif != FIF_UNKNOWN && FreeImage_FIFSupportsReading(fif)) { pBitmap = FreeImage_Load(fif, a_szTexture); } // Failure if (pBitmap == nullptr) { printf("Error: Failed to load image '%s'!\n", a_szTexture); return 0; } // Force the image to RGBA // Get size of pixel in bits unsigned int bpp = FreeImage_GetBPP(pBitmap); /* // How does this conversion to RGBA work? if( a_uiBPP != nullptr ) { *a_uiBPP = bpp/8; //RGBA has 8 bits per color channel... } */ // Get Color Type FREE_IMAGE_COLOR_TYPE fi_colourType = FreeImage_GetColorType(pBitmap); if (fi_colourType != FIC_RGBALPHA ) { FIBITMAP* ndib = FreeImage_ConvertTo32Bits(pBitmap); FreeImage_Unload(pBitmap); pBitmap = ndib; bpp = FreeImage_GetBPP(pBitmap); fi_colourType = FreeImage_GetColorType(pBitmap); } // get the pixel data BYTE* pData = FreeImage_GetBits(pBitmap); // try to determine data type of file (bytes/floats) FREE_IMAGE_TYPE fit = FreeImage_GetImageType(pBitmap); // VARIABLE = ( CONDITION TO EVALUATE ) ? IF_TRUE : IF_FALSE ; GLenum eType = (fit == FIT_RGBF || fit == FIT_FLOAT) ? GL_FLOAT:GL_UNSIGNED_BYTE; // Create variable to store OGL Tex ID GLuint textureID; // Generate OGL Tex ID glGenTextures( 1, &textureID ); // Bind Texture for Use by using the OGL Tex DI glBindTexture( GL_TEXTURE_2D, textureID ); // Texturing allows elements of an image array to be read by shaders. glTexImage2D( GL_TEXTURE_2D, // TARGET 0, // level of detail GL_RGBA, // color format FreeImage_GetWidth(pBitmap), // width FreeImage_GetHeight(pBitmap), // height 0, // border (must be 0) fi_colourType, // pixel data format - i.e. RGBA eType, // pixel data type pData); // data // specify default filtering and wrapping glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); // unbind texture glBindTexture( GL_TEXTURE_2D, 0 ); // delete data FreeImage_Unload(pBitmap); return textureID; }
/** Image rotation using a 3rd order (cubic) B-Splines. @param dib Input dib (8, 24 or 32-bit) @param angle Output image rotation @param x_shift Output image horizontal shift @param y_shift Output image vertical shift @param x_origin Output origin of the x-axis @param y_origin Output origin of the y-axis @param use_mask Whether or not to mask the image @return Returns the translated & rotated dib if successful, returns NULL otherwise */ FIBITMAP * DLL_CALLCONV FreeImage_RotateEx(FIBITMAP *dib, double angle, double x_shift, double y_shift, double x_origin, double y_origin, BOOL use_mask) { int x, y, bpp; int channel, nb_channels; BYTE *src_bits, *dst_bits; FIBITMAP *src8 = NULL, *dst8 = NULL, *dst = NULL; try { bpp = FreeImage_GetBPP(dib); if(bpp == 8) { return Rotate8Bit(dib, angle, x_shift, y_shift, x_origin, y_origin, ROTATE_CUBIC, use_mask); } if((bpp == 24) || (bpp == 32)) { // allocate dst image int width = FreeImage_GetWidth(dib); int height = FreeImage_GetHeight(dib); if( bpp == 24 ) { dst = FreeImage_Allocate(width, height, bpp, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } else { dst = FreeImage_Allocate(width, height, bpp, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } if(!dst) throw(1); // allocate a temporary 8-bit dib (no need to build a palette) src8 = FreeImage_Allocate(width, height, 8); if(!src8) throw(1); // process each channel separately // ------------------------------- nb_channels = (bpp / 8); for(channel = 0; channel < nb_channels; channel++) { // extract channel from source dib for(y = 0; y < height; y++) { src_bits = FreeImage_GetScanLine(dib, y); dst_bits = FreeImage_GetScanLine(src8, y); for(x = 0; x < width; x++) { dst_bits[x] = src_bits[channel]; src_bits += nb_channels; } } // process channel dst8 = Rotate8Bit(src8, angle, x_shift, y_shift, x_origin, y_origin, ROTATE_CUBIC, use_mask); if(!dst8) throw(1); // insert channel to destination dib for(y = 0; y < height; y++) { src_bits = FreeImage_GetScanLine(dst8, y); dst_bits = FreeImage_GetScanLine(dst, y); for(x = 0; x < width; x++) { dst_bits[channel] = src_bits[x]; dst_bits += nb_channels; } } FreeImage_Unload(dst8); } FreeImage_Unload(src8); return dst; } } catch(int) { if(src8) FreeImage_Unload(src8); if(dst8) FreeImage_Unload(dst8); if(dst) FreeImage_Unload(dst); } return NULL; }
/** Image translation and rotation using B-Splines. @param dib Input 8-bit greyscale image @param angle Output image rotation in degree @param x_shift Output image horizontal shift @param y_shift Output image vertical shift @param x_origin Output origin of the x-axis @param y_origin Output origin of the y-axis @param spline_degree Output degree of the B-spline model @param use_mask Whether or not to mask the image @return Returns the translated & rotated dib if successful, returns NULL otherwise */ static FIBITMAP * Rotate8Bit(FIBITMAP *dib, double angle, double x_shift, double y_shift, double x_origin, double y_origin, long spline_degree, BOOL use_mask) { double *ImageRasterArray; double p; double a11, a12, a21, a22; double x0, y0, x1, y1; long x, y; long spline; bool bResult; int bpp = FreeImage_GetBPP(dib); if(bpp != 8) { return NULL; } int width = FreeImage_GetWidth(dib); int height = FreeImage_GetHeight(dib); switch(spline_degree) { case ROTATE_QUADRATIC: spline = 2L; // Use splines of degree 2 (quadratic interpolation) break; case ROTATE_CUBIC: spline = 3L; // Use splines of degree 3 (cubic interpolation) break; case ROTATE_QUARTIC: spline = 4L; // Use splines of degree 4 (quartic interpolation) break; case ROTATE_QUINTIC: spline = 5L; // Use splines of degree 5 (quintic interpolation) break; default: spline = 3L; } // allocate output image FIBITMAP *dst = FreeImage_Allocate(width, height, bpp); if(!dst) return NULL; // buid a grey scale palette RGBQUAD *pal = FreeImage_GetPalette(dst); for(int i = 0; i < 256; i++) { pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (BYTE)i; } // allocate a temporary array ImageRasterArray = (double*)malloc(width * height * sizeof(double)); if(!ImageRasterArray) { FreeImage_Unload(dst); return NULL; } // copy data samples for(y = 0; y < height; y++) { double *pImage = &ImageRasterArray[y*width]; BYTE *src_bits = FreeImage_GetScanLine(dib, height-1-y); for(x = 0; x < width; x++) { pImage[x] = (double)src_bits[x]; } } // convert between a representation based on image samples // and a representation based on image B-spline coefficients bResult = SamplesToCoefficients(ImageRasterArray, width, height, spline); if(!bResult) { FreeImage_Unload(dst); free(ImageRasterArray); return NULL; } // prepare the geometry angle *= PI / 180.0; a11 = cos(angle); a12 = -sin(angle); a21 = sin(angle); a22 = cos(angle); x0 = a11 * (x_shift + x_origin) + a12 * (y_shift + y_origin); y0 = a21 * (x_shift + x_origin) + a22 * (y_shift + y_origin); x_shift = x_origin - x0; y_shift = y_origin - y0; // visit all pixels of the output image and assign their value for(y = 0; y < height; y++) { BYTE *dst_bits = FreeImage_GetScanLine(dst, height-1-y); x0 = a12 * (double)y + x_shift; y0 = a22 * (double)y + y_shift; for(x = 0; x < width; x++) { x1 = x0 + a11 * (double)x; y1 = y0 + a21 * (double)x; if(use_mask) { if((x1 <= -0.5) || (((double)width - 0.5) <= x1) || (y1 <= -0.5) || (((double)height - 0.5) <= y1)) { p = 0; } else { p = (double)InterpolatedValue(ImageRasterArray, width, height, x1, y1, spline); } } else { p = (double)InterpolatedValue(ImageRasterArray, width, height, x1, y1, spline); } // clamp and convert to BYTE dst_bits[x] = (BYTE)MIN(MAX((int)0, (int)(p + 0.5)), (int)255); } } // free working array and return free(ImageRasterArray); return dst; }
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 && header->m_filename) { 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 if(header->m_filename) delete[] header->m_filename; // delete the FIMULTIBITMAPHEADER delete header; } delete bitmap; return success; } return FALSE; }
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; }
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); } } }
BOOL DLL_CALLCONV FreeImage_CloseMultiBitmap(FIMULTIBITMAP *bitmap, int flags) { if (bitmap) { BOOL success = TRUE; if (bitmap->data) { MULTIBITMAPHEADER *header = FreeImage_GetMultiBitmapHeader(bitmap); // saves changes only of images loaded directly from a file if (header->changed && header->m_filename) { try { // open a temp file std::string spool_name; ReplaceExtension(spool_name, header->m_filename, "fispool"); // open the spool file and the source file FILE *f = fopen(spool_name.c_str(), "w+b"); // saves changes if (f == NULL) { FreeImage_OutputMessageProc(header->fif, "Failed to open %s, %s", spool_name.c_str(), strerror(errno)); success = FALSE; } else { success = FreeImage_SaveMultiBitmapToHandle(header->fif, bitmap, header->io, (fi_handle)f, flags); // close the files if (fclose(f) != 0) { success = FALSE; FreeImage_OutputMessageProc(header->fif, "Failed to close %s, %s", spool_name.c_str(), strerror(errno)); } } if (header->handle) { fclose((FILE *)header->handle); } // applies changes to the destination file if (success) { remove(header->m_filename); success = (rename(spool_name.c_str(), header->m_filename) == 0) ? TRUE:FALSE; if(!success) { FreeImage_OutputMessageProc(header->fif, "Failed to rename %s to %s", spool_name.c_str(), header->m_filename); } } else { remove(spool_name.c_str()); } } catch (std::bad_alloc &) { success = FALSE; } } else { if (header->handle && header->m_filename) { 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 if(header->m_filename) { delete[] header->m_filename; } // delete the FIMULTIBITMAPHEADER delete header; } delete bitmap; return success; } return FALSE; }
int psdThumbnail::Read(FreeImageIO *io, fi_handle handle, int iResourceSize, bool isBGR) { BYTE ShortValue[2], IntValue[4]; int nBytes=0, n; // remove the header size (28 bytes) from the total data size int iTotalData = iResourceSize - 28; const long block_end = io->tell_proc(handle) + iTotalData; n = (int)io->read_proc(&IntValue, sizeof(IntValue), 1, handle); nBytes += n * sizeof(IntValue); _Format = psdGetValue(IntValue, sizeof(_Format) ); n = (int)io->read_proc(&IntValue, sizeof(IntValue), 1, handle); nBytes += n * sizeof(IntValue); _Width = psdGetValue(IntValue, sizeof(_Width) ); n = (int)io->read_proc(&IntValue, sizeof(IntValue), 1, handle); nBytes += n * sizeof(IntValue); _Height = psdGetValue(IntValue, sizeof(_Height) ); n = (int)io->read_proc(&IntValue, sizeof(IntValue), 1, handle); nBytes += n * sizeof(IntValue); _WidthBytes = psdGetValue(IntValue, sizeof(_WidthBytes) ); n = (int)io->read_proc(&IntValue, sizeof(IntValue), 1, handle); nBytes += n * sizeof(IntValue); _Size = psdGetValue(IntValue, sizeof(_Size) ); n = (int)io->read_proc(&IntValue, sizeof(IntValue), 1, handle); nBytes += n * sizeof(IntValue); _CompressedSize = psdGetValue(IntValue, sizeof(_CompressedSize) ); n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle); nBytes += n * sizeof(ShortValue); _BitPerPixel = (short)psdGetValue(ShortValue, sizeof(_BitPerPixel) ); n = (int)io->read_proc(&ShortValue, sizeof(ShortValue), 1, handle); nBytes += n * sizeof(ShortValue); _Planes = (short)psdGetValue(ShortValue, sizeof(_Planes) ); const long JFIF_startpos = io->tell_proc(handle); if(_dib) { FreeImage_Unload(_dib); } if(_Format == 1) { // kJpegRGB thumbnail image _dib = FreeImage_LoadFromHandle(FIF_JPEG, io, handle); if(isBGR) { SwapRedBlue32(_dib); } // HACK: manually go to end of thumbnail, because (for some reason) LoadFromHandle consumes more bytes then available! io->seek_proc(handle, block_end, SEEK_SET); } else { // kRawRGB thumbnail image // ### Unimplemented (should be trivial) // skip the thumbnail part io->seek_proc(handle, iTotalData, SEEK_CUR); return iResourceSize; } nBytes += (block_end - JFIF_startpos); return nBytes; }
int main(int argc, char *argv[]) { const char *input_dir = "d:\\images\\"; FIBITMAP *dib = NULL; int id = 1; // call this ONLY when linking with FreeImage as a static library #ifdef FREEIMAGE_LIB FreeImage_Initialise(); #endif // FREEIMAGE_LIB // initialize your own FreeImage error handler FreeImage_SetOutputMessage(FreeImageErrorHandler); // print version & copyright infos printf(FreeImage_GetVersion()); printf("\n"); printf(FreeImage_GetCopyrightMessage()); printf("\n"); // open the log file FILE *log_file = fopen("log_file.txt", "w"); // batch convert all supported bitmaps _finddata_t finddata; long handle; char image_path[MAX_PATH]; // scan all files strcpy(image_path, input_dir); strcat(image_path, "*.*"); if ((handle = _findfirst(image_path, &finddata)) != -1) { do { // make a path to a directory char *directory = new char[MAX_PATH]; strcpy(directory, input_dir); strcat(directory, finddata.name); // make a unique filename char *unique = new char[128]; itoa(id, unique, 10); strcat(unique, ".png"); // open and load the file using the default load option dib = GenericLoader(directory, 0); if (dib != NULL) { // save the file as PNG bool bSuccess = GenericWriter(dib, unique, PNG_DEFAULT); // free the dib FreeImage_Unload(dib); if(bSuccess) { fwrite(unique, strlen(unique), 1, log_file); } else { strcpy(unique, "FAILED"); fwrite(unique, strlen(unique), 1, log_file); } fwrite(" >> ", 4, 1, log_file); fwrite(directory, strlen(directory), 1, log_file); fwrite("\n", 1, 1, log_file); id++; } delete [] unique; delete [] directory; } while (_findnext(handle, &finddata) == 0); _findclose(handle); } fclose(log_file); // call this ONLY when linking with FreeImage as a static library #ifdef FREEIMAGE_LIB FreeImage_DeInitialise(); #endif // FREEIMAGE_LIB return 0; }
/** Compute the gradient attenuation function PHI(x, y) @param gradients Gradient pyramid (nlevels levels) @param avgGrad Average gradient on each level (array of size nlevels) @param nlevels Number of levels @param alpha Parameter alpha in the paper @param beta Parameter beta in the paper @return Returns the attenuation matrix Phi if successful, returns NULL otherwise */ static FIBITMAP* PhiMatrix(FIBITMAP **gradients, float *avgGrad, int nlevels, float alpha, float beta) { float *src_pixel, *dst_pixel; FIBITMAP **phi = NULL; try { phi = (FIBITMAP**)malloc(nlevels * sizeof(FIBITMAP*)); if(!phi) throw(1); memset(phi, 0, nlevels * sizeof(FIBITMAP*)); for(int k = nlevels-1; k >= 0; k--) { // compute phi(k) FIBITMAP *Gk = gradients[k]; const unsigned width = FreeImage_GetWidth(Gk); const unsigned height = FreeImage_GetHeight(Gk); const unsigned pitch = FreeImage_GetPitch(Gk) / sizeof(float); // parameter alpha is 0.1 times the average gradient magnitude // also, note the factor of 2**k in the denominator; // that is there to correct for the fact that an average gradient avgGrad(H) over 2**k pixels // in the original image will appear as a gradient grad(Hk) = 2**k*avgGrad(H) over a single pixel in Hk. float ALPHA = alpha * avgGrad[k] * (float)((int)1 << k); if(ALPHA == 0) ALPHA = EPSILON; phi[k] = FreeImage_AllocateT(FIT_FLOAT, width, height); if(!phi[k]) throw(1); src_pixel = (float*)FreeImage_GetBits(Gk); dst_pixel = (float*)FreeImage_GetBits(phi[k]); for(unsigned y = 0; y < height; y++) { for(unsigned x = 0; x < width; x++) { // compute (alpha / grad) * (grad / alpha) ** beta const float v = src_pixel[x] / ALPHA; const float value = (float)pow((float)v, (float)(beta-1)); dst_pixel[x] = (value > 1) ? 1 : value; } // next line src_pixel += pitch; dst_pixel += pitch; } if(k < nlevels-1) { // compute PHI(k) = L( PHI(k+1) ) * phi(k) FIBITMAP *L = FreeImage_Rescale(phi[k+1], width, height, FILTER_BILINEAR); if(!L) throw(1); src_pixel = (float*)FreeImage_GetBits(L); dst_pixel = (float*)FreeImage_GetBits(phi[k]); for(unsigned y = 0; y < height; y++) { for(unsigned x = 0; x < width; x++) { dst_pixel[x] *= src_pixel[x]; } // next line src_pixel += pitch; dst_pixel += pitch; } FreeImage_Unload(L); // PHI(k+1) is no longer needed FreeImage_Unload(phi[k+1]); phi[k+1] = NULL; } // next level } // get the final result and return FIBITMAP *dst = phi[0]; free(phi); return dst; } catch(int) { if(phi) { for(int k = nlevels-1; k >= 0; k--) { if(phi[k]) FreeImage_Unload(phi[k]); } free(phi); } return NULL; } }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { mng_handle hmng = NULL; if (handle != NULL) { try { // allocate our stream data structure mngstuff *mymng = (mngstuff *)data; // set up the mng decoder for our stream hmng = mng_initialize(mymng, mymngalloc, mymngfree, MNG_NULL); if (hmng == MNG_NULL) { throw "could not initialize libmng"; } // set the colorprofile, lcms uses this mng_set_srgb(hmng, MNG_TRUE ); // set white as background color WORD wRed, wGreen, wBlue; wRed = wGreen = wBlue = (255 << 8) + 255; mng_set_bgcolor(hmng, wRed, wGreen, wBlue); // if PNG Background is available, use it mng_set_usebkgd(hmng, MNG_TRUE ); // no need to store chunks mng_set_storechunks(hmng, MNG_FALSE); // no need to wait: straight reading mng_set_suspensionmode(hmng, MNG_FALSE); // set the callbacks mng_setcb_errorproc(hmng, mymngerror); mng_setcb_openstream(hmng, mymngopenstream); mng_setcb_closestream(hmng, mymngclosestream); mng_setcb_readdata(hmng, mymngreadstream); mng_setcb_processheader(hmng, mymngprocessheader); mng_setcb_getcanvasline(hmng, mymnggetcanvasline); mng_setcb_refresh(hmng, mymngrefresh); mng_setcb_gettickcount(hmng, mymnggetticks); mng_setcb_settimer(hmng, mymngsettimer); // read in the bitmap mng_readdisplay(hmng); // read all bitmaps int retval = MNG_NOERROR; mng_datap pData = (mng_datap)hmng; while(pData->bReading) { retval = mng_display_resume(hmng); if((retval == MNG_NEEDTIMERWAIT) || (retval == MNG_FUNCTIONINVALID)) break; } // temp store the newly created bitmap FIBITMAP *bitmap = mymng->bitmap; // cleanup and return the temp stored bitmap mng_cleanup(&hmng); return bitmap; } catch (const char *message) { FIBITMAP *bitmap = ((mngstuff *)mng_get_userdata(hmng))->bitmap; if(bitmap) { FreeImage_Unload(bitmap); } mng_cleanup(&hmng); FreeImage_OutputMessageProc(s_format_id, message); } } return NULL; }
/** Performs a 5 by 5 gaussian filtering using two 1D convolutions, followed by a subsampling by 2. @param dib Input image @return Returns a blurred image of size SIZE(dib)/2 @see GaussianPyramid */ static FIBITMAP* GaussianLevel5x5(FIBITMAP *dib) { FIBITMAP *h_dib = NULL, *v_dib = NULL, *dst = NULL; float *src_pixel, *dst_pixel; try { const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); if(image_type != FIT_FLOAT) throw(1); const unsigned width = FreeImage_GetWidth(dib); const unsigned height = FreeImage_GetHeight(dib); h_dib = FreeImage_AllocateT(image_type, width, height); v_dib = FreeImage_AllocateT(image_type, width, height); if(!h_dib || !v_dib) throw(1); const unsigned pitch = FreeImage_GetPitch(dib) / sizeof(float); // horizontal convolution dib -> h_dib src_pixel = (float*)FreeImage_GetBits(dib); dst_pixel = (float*)FreeImage_GetBits(h_dib); for(unsigned y = 0; y < height; y++) { // work on line y for(unsigned x = 2; x < width - 2; x++) { dst_pixel[x] = src_pixel[x-2] + src_pixel[x+2] + 4 * (src_pixel[x-1] + src_pixel[x+1]) + 6 * src_pixel[x]; dst_pixel[x] /= 16; } // boundary mirroring dst_pixel[0] = (2 * src_pixel[2] + 8 * src_pixel[1] + 6 * src_pixel[0]) / 16; dst_pixel[1] = (src_pixel[3] + 4 * (src_pixel[0] + src_pixel[2]) + 7 * src_pixel[1]) / 16; dst_pixel[width-2] = (src_pixel[width-4] + 5 * src_pixel[width-1] + 4 * src_pixel[width-3] + 6 * src_pixel[width-2]) / 16; dst_pixel[width-1] = (src_pixel[width-3] + 5 * src_pixel[width-2] + 10 * src_pixel[width-1]) / 16; // next line src_pixel += pitch; dst_pixel += pitch; } // vertical convolution h_dib -> v_dib src_pixel = (float*)FreeImage_GetBits(h_dib); dst_pixel = (float*)FreeImage_GetBits(v_dib); for(unsigned x = 0; x < width; x++) { // work on column x for(unsigned y = 2; y < height - 2; y++) { const unsigned index = y*pitch + x; dst_pixel[index] = src_pixel[index-2*pitch] + src_pixel[index+2*pitch] + 4 * (src_pixel[index-pitch] + src_pixel[index+pitch]) + 6 * src_pixel[index]; dst_pixel[index] /= 16; } // boundary mirroring dst_pixel[x] = (2 * src_pixel[x+2*pitch] + 8 * src_pixel[x+pitch] + 6 * src_pixel[x]) / 16; dst_pixel[x+pitch] = (src_pixel[x+3*pitch] + 4 * (src_pixel[x] + src_pixel[x+2*pitch]) + 7 * src_pixel[x+pitch]) / 16; dst_pixel[(height-2)*pitch+x] = (src_pixel[(height-4)*pitch+x] + 5 * src_pixel[(height-1)*pitch+x] + 4 * src_pixel[(height-3)*pitch+x] + 6 * src_pixel[(height-2)*pitch+x]) / 16; dst_pixel[(height-1)*pitch+x] = (src_pixel[(height-3)*pitch+x] + 5 * src_pixel[(height-2)*pitch+x] + 10 * src_pixel[(height-1)*pitch+x]) / 16; } FreeImage_Unload(h_dib); h_dib = NULL; // perform downsampling dst = FreeImage_Rescale(v_dib, width/2, height/2, FILTER_BILINEAR); FreeImage_Unload(v_dib); return dst; } catch(int) { if(h_dib) FreeImage_Unload(h_dib); if(v_dib) FreeImage_Unload(v_dib); if(dst) FreeImage_Unload(dst); return NULL; } }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { png_structp png_ptr = NULL; png_infop info_ptr; png_uint_32 width, height; png_colorp png_palette = NULL; int color_type, palette_entries = 0; int bit_depth, pixel_depth; // pixel_depth = bit_depth * channels FIBITMAP *dib = NULL; RGBQUAD *palette = NULL; // pointer to dib palette png_bytepp row_pointers = NULL; int i; fi_ioStructure fio; fio.s_handle = handle; fio.s_io = io; if (handle) { BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS; try { // check to see if the file is in fact a PNG file BYTE png_check[PNG_BYTES_TO_CHECK]; io->read_proc(png_check, PNG_BYTES_TO_CHECK, 1, handle); if (png_sig_cmp(png_check, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) { return NULL; // Bad signature } // create the chunk manage structure png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler); if (!png_ptr) { return NULL; } // create the info structure info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); return NULL; } // init the IO png_set_read_fn(png_ptr, &fio, _ReadProc); if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); return NULL; } // because we have already read the signature... png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); // read the IHDR chunk png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); pixel_depth = png_get_bit_depth(png_ptr, info_ptr) * png_get_channels(png_ptr, info_ptr); // get image data type (assume standard image type) FREE_IMAGE_TYPE image_type = FIT_BITMAP; if (bit_depth == 16) { if ((pixel_depth == 16) && (color_type == PNG_COLOR_TYPE_GRAY)) { image_type = FIT_UINT16; } else if ((pixel_depth == 48) && (color_type == PNG_COLOR_TYPE_RGB)) { image_type = FIT_RGB16; } else if ((pixel_depth == 64) && (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) { image_type = FIT_RGBA16; } else { // tell libpng to strip 16 bit/color files down to 8 bits/color png_set_strip_16(png_ptr); bit_depth = 8; } } #ifndef FREEIMAGE_BIGENDIAN if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) { // turn on 16 bit byte swapping png_set_swap(png_ptr); } #endif // set some additional flags switch(color_type) { case PNG_COLOR_TYPE_RGB: case PNG_COLOR_TYPE_RGB_ALPHA: #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // flip the RGB pixels to BGR (or RGBA to BGRA) if(image_type == FIT_BITMAP) { png_set_bgr(png_ptr); } #endif break; case PNG_COLOR_TYPE_PALETTE: // expand palette images to the full 8 bits from 2 bits/pixel if (pixel_depth == 2) { png_set_packing(png_ptr); pixel_depth = 8; } break; case PNG_COLOR_TYPE_GRAY: // expand grayscale images to the full 8 bits from 2 bits/pixel // but *do not* expand fully transparent palette entries to a full alpha channel if (pixel_depth == 2) { png_set_expand_gray_1_2_4_to_8(png_ptr); pixel_depth = 8; } break; case PNG_COLOR_TYPE_GRAY_ALPHA: // expand 8-bit greyscale + 8-bit alpha to 32-bit png_set_gray_to_rgb(png_ptr); #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR // flip the RGBA pixels to BGRA png_set_bgr(png_ptr); #endif pixel_depth = 32; break; default: throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } // unlike the example in the libpng documentation, we have *no* idea where // this file may have come from--so if it doesn't have a file gamma, don't // do any correction ("do no harm") if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) { double gamma = 0; double screen_gamma = 2.2; if (png_get_gAMA(png_ptr, info_ptr, &gamma) && ( flags & PNG_IGNOREGAMMA ) != PNG_IGNOREGAMMA) { png_set_gamma(png_ptr, screen_gamma, gamma); } } // all transformations have been registered; now update info_ptr data png_read_update_info(png_ptr, info_ptr); // color type may have changed, due to our transformations color_type = png_get_color_type(png_ptr,info_ptr); // create a DIB and write the bitmap header // set up the DIB palette, if needed switch (color_type) { case PNG_COLOR_TYPE_RGB: png_set_invert_alpha(png_ptr); if(image_type == FIT_BITMAP) { dib = FreeImage_AllocateHeader(header_only, width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } else { dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth); } break; case PNG_COLOR_TYPE_RGB_ALPHA: if(image_type == FIT_BITMAP) { dib = FreeImage_AllocateHeader(header_only, width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } else { dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth); } break; case PNG_COLOR_TYPE_PALETTE: dib = FreeImage_AllocateHeader(header_only, width, height, pixel_depth); png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries); palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib)); palette = FreeImage_GetPalette(dib); // store the palette for (i = 0; i < palette_entries; i++) { palette[i].rgbRed = png_palette[i].red; palette[i].rgbGreen = png_palette[i].green; palette[i].rgbBlue = png_palette[i].blue; } break; case PNG_COLOR_TYPE_GRAY: dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth); if(pixel_depth <= 8) { palette = FreeImage_GetPalette(dib); palette_entries = 1 << pixel_depth; for (i = 0; i < palette_entries; i++) { palette[i].rgbRed = palette[i].rgbGreen = palette[i].rgbBlue = (BYTE)((i * 255) / (palette_entries - 1)); } } break; default: throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } // store the transparency table if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { // array of alpha (transparency) entries for palette png_bytep trans_alpha = NULL; // number of transparent entries int num_trans = 0; // graylevel or color sample values of the single transparent color for non-paletted images png_color_16p trans_color = NULL; png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color); if((color_type == PNG_COLOR_TYPE_GRAY) && trans_color) { // single transparent color if (trans_color->gray < palette_entries) { BYTE table[256]; memset(table, 0xFF, palette_entries); table[trans_color->gray] = 0; FreeImage_SetTransparencyTable(dib, table, palette_entries); } } else if((color_type == PNG_COLOR_TYPE_PALETTE) && trans_alpha) { // transparency table FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans); } } // store the background color if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) { // Get the background color to draw transparent and alpha images over. // Note that even if the PNG file supplies a background, you are not required to // use it - you should use the (solid) application background if it has one. png_color_16p image_background = NULL; RGBQUAD rgbBkColor; if (png_get_bKGD(png_ptr, info_ptr, &image_background)) { rgbBkColor.rgbRed = (BYTE)image_background->red; rgbBkColor.rgbGreen = (BYTE)image_background->green; rgbBkColor.rgbBlue = (BYTE)image_background->blue; rgbBkColor.rgbReserved = 0; FreeImage_SetBackgroundColor(dib, &rgbBkColor); } } // get physical resolution if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) { png_uint_32 res_x, res_y; // we'll overload this var and use 0 to mean no phys data, // since if it's not in meters we can't use it anyway int res_unit_type = PNG_RESOLUTION_UNKNOWN; png_get_pHYs(png_ptr,info_ptr, &res_x, &res_y, &res_unit_type); if (res_unit_type == PNG_RESOLUTION_METER) { FreeImage_SetDotsPerMeterX(dib, res_x); FreeImage_SetDotsPerMeterY(dib, res_y); } } // get possible ICC profile if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) { png_charp profile_name = NULL; png_bytep profile_data = NULL; png_uint_32 profile_length = 0; int compression_type; png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &profile_length); // copy ICC profile data (must be done after FreeImage_AllocateHeader) FreeImage_CreateICCProfile(dib, profile_data, profile_length); } // --- header only mode => clean-up and return if (header_only) { // get possible metadata (it can be located both before and after the image data) ReadMetadata(png_ptr, info_ptr, dib); if (png_ptr) { // clean up after the read, and free any memory allocated - REQUIRED png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } return dib; } // set the individual row_pointers to point at the correct offsets row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep)); if (!row_pointers) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); FreeImage_Unload(dib); return NULL; } // read in the bitmap bits via the pointer table // allow loading of PNG with minor errors (such as images with several IDAT chunks) for (png_uint_32 k = 0; k < height; k++) { row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k); } png_set_benign_errors(png_ptr, 1); png_read_image(png_ptr, row_pointers); // check if the bitmap contains transparency, if so enable it in the header if (FreeImage_GetBPP(dib) == 32) { if (FreeImage_GetColorType(dib) == FIC_RGBALPHA) { FreeImage_SetTransparent(dib, TRUE); } else { FreeImage_SetTransparent(dib, FALSE); } } // cleanup if (row_pointers) { free(row_pointers); row_pointers = NULL; } // read the rest of the file, getting any additional chunks in info_ptr png_read_end(png_ptr, info_ptr); // get possible metadata (it can be located both before and after the image data) ReadMetadata(png_ptr, info_ptr, dib); if (png_ptr) { // clean up after the read, and free any memory allocated - REQUIRED png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } return dib; } catch (const char *text) { if (png_ptr) { png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); } if (row_pointers) { free(row_pointers); } if (dib) { FreeImage_Unload(dib); } FreeImage_OutputMessageProc(s_format_id, text); return NULL; } } return NULL; }
/** Apply the Gradient Domain High Dynamic Range Compression to a RGBF image and convert to 24-bit RGB @param dib Input RGBF / RGB16 image @param color_saturation Color saturation (s parameter in the paper) in [0.4..0.6] @param attenuation Atenuation factor (beta parameter in the paper) in [0.8..0.9] @return Returns a 24-bit RGB image if successful, returns NULL otherwise */ FIBITMAP* DLL_CALLCONV FreeImage_TmoFattal02(FIBITMAP *dib, double color_saturation, double attenuation) { const float alpha = 0.1F; // parameter alpha = 0.1 const float beta = (float)MAX(0.8, MIN(0.9, attenuation)); // parameter beta = [0.8..0.9] const float s = (float)MAX(0.4, MIN(0.6, color_saturation));// exponent s controls color saturation = [0.4..0.6] FIBITMAP *src = NULL; FIBITMAP *Yin = NULL; FIBITMAP *Yout = NULL; FIBITMAP *dst = NULL; if(!FreeImage_HasPixels(dib)) return NULL; try { // convert to RGBF src = FreeImage_ConvertToRGBF(dib); if(!src) throw(1); // get the luminance channel Yin = ConvertRGBFToY(src); if(!Yin) throw(1); // perform the tone mapping Yout = tmoFattal02(Yin, alpha, beta); if(!Yout) throw(1); // clip low and high values and normalize to [0..1] //NormalizeY(Yout, 0.001F, 0.995F); NormalizeY(Yout, 0, 1); // compress the dynamic range const unsigned width = FreeImage_GetWidth(src); const unsigned height = FreeImage_GetHeight(src); const unsigned rgb_pitch = FreeImage_GetPitch(src); const unsigned y_pitch = FreeImage_GetPitch(Yin); BYTE *bits = (BYTE*)FreeImage_GetBits(src); BYTE *bits_yin = (BYTE*)FreeImage_GetBits(Yin); BYTE *bits_yout = (BYTE*)FreeImage_GetBits(Yout); for(unsigned y = 0; y < height; y++) { float *Lin = (float*)bits_yin; float *Lout = (float*)bits_yout; float *color = (float*)bits; for(unsigned x = 0; x < width; x++) { for(unsigned c = 0; c < 3; c++) { *color = (Lin[x] > 0) ? pow(*color/Lin[x], s) * Lout[x] : 0; color++; } } bits += rgb_pitch; bits_yin += y_pitch; bits_yout += y_pitch; } // not needed anymore FreeImage_Unload(Yin); Yin = NULL; FreeImage_Unload(Yout); Yout = NULL; // clamp image highest values to display white, then convert to 24-bit RGB dst = ClampConvertRGBFTo24(src); // clean-up and return FreeImage_Unload(src); src = NULL; // copy metadata from src to dst FreeImage_CloneMetadata(dst, dib); return dst; } catch(int) { if(src) FreeImage_Unload(src); if(Yin) FreeImage_Unload(Yin); if(Yout) FreeImage_Unload(Yout); return NULL; } }
GLuint OGLRenderSystem::GetTextureCache( TextureBase* tex ) { GLuint& cache = (GLuint&)tex->mCache; if( tex->IsDirty( ) ) { if( cache ) { glDeleteTextures( 1, &cache ); cache = 0; } int texformat = tex->GetFormat( ); if( texformat == 0 ) { glGenTextures( 1, &cache ); if( !cache ) { printf( "Failed to generate texture :: cache = 0\n" ); return 0; } glBindTexture( GL_TEXTURE_2D, cache ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); DWORD dwFlags = *(DWORD*)(tex->mData + 0x50); if( dwFlags & 0x40 ) { DWORD bpp = *(DWORD*)(tex->mData + 0x58); int hasAlpha = dwFlags & 0x1; DWORD aMask = *(DWORD*)(tex->mData + 0x68); int type; int format; int data; if( bpp == 16 ) { if( aMask == 0x80 ) { //a1r5g5b5 format = GL_RGB5_A1; type = GL_BGRA; data = GL_UNSIGNED_SHORT_1_5_5_5_REV; } else { //a4r4g4b4 if( hasAlpha ) { format = GL_RGBA4; type = GL_BGRA; data = GL_UNSIGNED_SHORT_4_4_4_4_REV; } else { format = GL_RGB4; type = GL_BGR; data = GL_UNSIGNED_SHORT_4_4_4_4_REV; } } } else if( bpp == 32 ) { if( hasAlpha ) { format = GL_RGBA; type = GL_BGRA; data = GL_UNSIGNED_INT_8_8_8_8_REV; } else { format = GL_RGB; type = GL_BGR; data = GL_UNSIGNED_INT_8_8_8_8_REV; } } DWORD width = tex->GetWidth( ); DWORD height = tex->GetHeight( ); glTexImage2D( GL_TEXTURE_2D, 0, format, width, height, 0, type, data, (GLvoid*)(tex->mData + 0x80) ); } else { FIMEMORY* imgmem = FreeImage_OpenMemory( tex->mData, tex->mDataLen ); FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeFromMemory( imgmem ); FIBITMAP* img = FreeImage_LoadFromMemory( fif, imgmem, 0 ); FIBITMAP* temp = img; img = FreeImage_ConvertTo32Bits( img ); FreeImage_FlipVertical( img ); glTexImage2D( GL_TEXTURE_2D, 0, 4, FreeImage_GetWidth( img ), FreeImage_GetHeight( img ), 0, GL_BGRA, GL_UNSIGNED_BYTE, (GLvoid*)FreeImage_GetBits( img ) ); FreeImage_Unload( temp ); FreeImage_Unload( img ); FreeImage_CloseMemory( imgmem ); } } else if( texformat == TextureFormat::A8 ) { glGenTextures( 1, &cache ); glBindTexture( GL_TEXTURE_2D, cache ); glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA8, tex->GetWidth( ), tex->GetHeight( ), 0, GL_ALPHA, GL_UNSIGNED_BYTE, (GLvoid*)tex->mData ); } else { printf( "Failed to create Texture Cache :: Invalid format: %d\n", texformat ); return 0; } tex->SetDirty( false ); } return cache; };
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { if (handle) { opj_dparameters_t parameters; // decompression parameters opj_event_mgr_t event_mgr; // event manager opj_image_t *image = NULL; // decoded image BYTE *src = NULL; long file_length; opj_dinfo_t* dinfo = NULL; // handle to a decompressor opj_cio_t *cio = NULL; FIBITMAP *dib = NULL; // check the file format if(!Validate(io, handle)) { return NULL; } // 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 decoding parameters to default values opj_set_default_decoder_parameters(¶meters); try { // read the input file and put it in memory long start_pos = io->tell_proc(handle); io->seek_proc(handle, 0, SEEK_END); file_length = io->tell_proc(handle) - start_pos; io->seek_proc(handle, start_pos, SEEK_SET); src = (BYTE*)malloc(file_length * sizeof(BYTE)); if(!src) { throw FI_MSG_ERROR_MEMORY; } if(io->read_proc(src, 1, file_length, handle) < 1) { throw "Error while reading input stream"; } // decode the JPEG-2000 file // get a decoder handle dinfo = opj_create_decompress(CODEC_JP2); // catch events using our callbacks opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, NULL); // setup the decoder decoding parameters using user parameters opj_setup_decoder(dinfo, ¶meters); // open a byte stream cio = opj_cio_open((opj_common_ptr)dinfo, src, file_length); // decode the stream and fill the image structure image = opj_decode(dinfo, cio); if(!image) { throw "Failed to decode image!\n"; } // close the byte stream opj_cio_close(cio); cio = NULL; // free the memory containing the code-stream free(src); src = NULL; // free the codec context opj_destroy_decompress(dinfo); // create output image dib = J2KImageToFIBITMAP(s_format_id, image); if(!dib) throw "Failed to import JPEG2000 image"; // free image data structure opj_image_destroy(image); return dib; } catch (const char *text) { if(src) free(src); if(dib) FreeImage_Unload(dib); // free remaining structures opj_destroy_decompress(dinfo); opj_image_destroy(image); // close the byte stream if(cio) opj_cio_close(cio); FreeImage_OutputMessageProc(s_format_id, text); return NULL; } } return NULL; }
GXBOOL RenderTargetImpl::SaveToMemory(clstd::MemBuffer* pBuffer, GXLPCSTR pImageFormat) { GXSIZE sDimension; GXBOOL bval = TRUE; GXFormat format = m_pColorTexture->GetFormat(); m_pColorTexture->GetDimension(&sDimension); Texture* pReadBackTexture = NULL; GetColorTexture(&pReadBackTexture, GXResUsage::Read); Texture::MAPPED mapped; if(pReadBackTexture->Map(&mapped, GXResMap::Read)) { GXUINT bpp = GetBytesOfGraphicsFormat(format); GXLPVOID pSourceBits = mapped.pBits; GXINT nSourcePitch = mapped.Pitch; clstd::Image temp_image; FREE_IMAGE_TYPE fit = FIT_BITMAP; switch(format) { case Format_R8G8B8A8: temp_image.Set(sDimension.cx, sDimension.cy, "RGBA", 8, pSourceBits, nSourcePitch); break; case Format_B8G8R8X8: temp_image.Set(sDimension.cx, sDimension.cy, "BGRX", 8, pSourceBits, nSourcePitch); break; case Format_B8G8R8: temp_image.Set(sDimension.cx, sDimension.cy, "BGRX", 8, pSourceBits, nSourcePitch); break; case Format_R8: temp_image.Set(sDimension.cx, sDimension.cy, "R", 8, pSourceBits, nSourcePitch); break; case Format_R8G8: temp_image.Set(sDimension.cx, sDimension.cy, "RG", 8, pSourceBits, nSourcePitch); break; case Format_R32G32B32A32_Float: fit = FIT_RGBAF; break; case Format_R32: fit = FIT_FLOAT; break; } if(temp_image.GetDataSize() > 0) { temp_image.SetFormat("BGRA"); pSourceBits = temp_image.GetLine(0); nSourcePitch = temp_image.GetPitch(); bpp = temp_image.GetChannels(); } FIBITMAP* fibmp = (fit == FIT_BITMAP) ? FreeImage_Allocate(sDimension.cx, sDimension.cy, bpp * 8) : FreeImage_AllocateT(fit, sDimension.cx, sDimension.cy, bpp * 8); BYTE* pDest = FreeImage_GetBits(fibmp); GXINT nDestPitch = FreeImage_GetPitch(fibmp); pDest += nDestPitch * (sDimension.cy - 1); for(int y = 0; y < sDimension.cy; y++) { memcpy(pDest, pSourceBits, clMin(nDestPitch, nSourcePitch)); pDest -= nDestPitch; pSourceBits = reinterpret_cast<GXLPVOID>(reinterpret_cast<size_t>(pSourceBits) + nSourcePitch); } pReadBackTexture->Unmap(); FREE_IMAGE_FORMAT fi_format = FIF_UNKNOWN; clStringA strFormat = pImageFormat; strFormat.MakeUpper(); if(strFormat == "PNG") { fi_format = FIF_PNG; } else if(strFormat == "JPEG" || strFormat == "JPG") { fi_format = FIF_JPEG; } else if(strFormat == "TIF" || strFormat == "TIFF") { fi_format = FIF_TIFF; } else if(strFormat == "TGA") { fi_format = FIF_TARGA; } else if(strFormat == "BMP") { fi_format = FIF_BMP; } else if(strFormat == "EXR") { fi_format = FIF_EXR; } if(fi_format != FIF_UNKNOWN) { FIMEMORY* fimemory = FreeImage_OpenMemory(); if(FreeImage_SaveToMemory(fi_format, fibmp, fimemory)) { BYTE *pData; DWORD size_in_bytes; if(FreeImage_AcquireMemory(fimemory, &pData, &size_in_bytes)) { pBuffer->Resize(0, FALSE); pBuffer->Append(pData, size_in_bytes); } else { bval = FALSE; } } else { bval = FALSE; } FreeImage_CloseMemory(fimemory); } else { bval = FALSE; } FreeImage_Unload(fibmp); } SAFE_RELEASE(pReadBackTexture); return bval; }
// Load a texture from disk Texture::Texture(const std::string& filename, const TextureWrapMode wrap, const TextureFilterMode filter, const bool mip_map) { freeimage_init_lock_.lock(); if (!freeimage_init_) { freeimage_init_lock_.unlock(); throw std::wruntime_error("Texture::Texture() - ERROR: Please call " "initTextureSystem() before loading textures from file!"); } freeimage_init_lock_.unlock(); mip_map_ = mip_map; wrap_ = wrap; filter_ = filter; filename_ = filename; // Check if the file has any backslashes (these dont load on Mac OS X) size_t ind = filename_.find_first_of('\\'); while (ind != std::string::npos) { filename_[ind] = '/'; ind = filename_.find_first_of('\\'); } managed_ = false; from_file_ = true; generateTextureID(); // NEW CODE USING THE FREEIMAGE LIBRARY FREE_IMAGE_FORMAT fif = FIF_UNKNOWN; //image format FIBITMAP* dib = NULL; //pointer to the image, once loaded BYTE* fi_bits = NULL; //pointer to the image data // check the file signature and deduce its format fif = FreeImage_GetFileType(filename_.c_str(), 0); // if still unknown, try to guess the file format from the file extension if (fif == FIF_UNKNOWN) { fif = FreeImage_GetFIFFromFilename(filename_.c_str()); } // if still unkown, return failure if (fif == FIF_UNKNOWN) { throw wruntime_error(wstring(L"Texture() - ERROR: Cannot deduce format" L" of the file: ") + string_util::ToWideString(filename_)); } // check that FreeImage has reading capabilities and if so load the file if (FreeImage_FIFSupportsReading(fif)) { dib = FreeImage_Load(fif, filename_.c_str()); } //if the image failed to load, return failure if (!dib) { throw wruntime_error(wstring(L"Texture() - ERROR: FreeImage couldn't " L"load the file: ") + string_util::ToWideString(filename_)); } // Convert everything to RGBA: unsigned int nbits = FreeImage_GetBPP(dib); if (nbits != 32) { FIBITMAP* old_dib = dib; dib = FreeImage_ConvertTo32Bits(old_dib); FreeImage_Unload(old_dib); } FreeImage_FlipVertical(dib); //retrieve the image data fi_bits = FreeImage_GetBits(dib); //get the image width and height w_ = FreeImage_GetWidth(dib); h_ = FreeImage_GetHeight(dib); // if this somehow one of these failed (they shouldn't), return failure if ((fi_bits == 0) || (w_ == 0) || (h_ == 0)) { throw wruntime_error(wstring(L"Texture() - ERROR: FreeImage couldn't " L"load the file: ") + string_util::ToWideString(filename)); } // Copy it into memory and leave it there in case we need it later. bits_ = new unsigned char[w_ * h_ * 4]; memcpy(bits_, fi_bits, sizeof(bits_[0]) * w_ * h_ * 4); format_internal_ = GL_RGBA; format_ = GL_BGRA; // FreeImage has bits flipped! type_ = GL_UNSIGNED_BYTE; dirty_data_ = true; sync(); // Sync anyway on startup (fixes some shutdown bugs) // Free FreeImage's copy of the data FreeImage_Unload(dib); // Unbind the texture so no one accidently makes changes to it GLState::glsBindTexture(GL_TEXTURE_2D, 0); }
void GraphicsHelps::closeImage(FIBITMAP *img) { FreeImage_Unload(img); }