BOOL fipImage::setSize(FREE_IMAGE_TYPE image_type, WORD width, WORD height, WORD bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask) { if(_dib) { FreeImage_Unload(_dib); } if((_dib = FreeImage_AllocateT(image_type, width, height, bpp, red_mask, green_mask, blue_mask)) == NULL) return FALSE; if(image_type == FIT_BITMAP) { // Create palette if needed switch(bpp) { case 1: case 4: case 8: RGBQUAD *pal = FreeImage_GetPalette(_dib); for(unsigned i = 0; i < FreeImage_GetColorsUsed(_dib); i++) { pal[i].rgbRed = i; pal[i].rgbGreen = i; pal[i].rgbBlue = i; } break; } } _bHasChanged = TRUE; return TRUE; }
BOOL DLL_CALLCONV FreeImage_GetBackgroundColor(FIBITMAP *dib, RGBQUAD *bkcolor) { if(dib && bkcolor) { if(FreeImage_HasBackgroundColor(dib)) { // get the background color RGBQUAD *bkgnd_color = &((FREEIMAGEHEADER *)dib->data)->bkgnd_color; memcpy(bkcolor, bkgnd_color, sizeof(RGBQUAD)); // get the background index if(FreeImage_GetBPP(dib) == 8) { RGBQUAD *pal = FreeImage_GetPalette(dib); for(unsigned i = 0; i < FreeImage_GetColorsUsed(dib); i++) { if(bkgnd_color->rgbRed == pal[i].rgbRed) { if(bkgnd_color->rgbGreen == pal[i].rgbGreen) { if(bkgnd_color->rgbBlue == pal[i].rgbBlue) { bkcolor->rgbReserved = i; return TRUE; } } } } } bkcolor->rgbReserved = 0; return TRUE; } } return FALSE; }
bool readImage(SImage& image, MemChunk& data, int index) { // Get image info SImage::info_t info; FIBITMAP* bm = getFIInfo(data, info); // Check it created/read ok if (!bm) { Global::error = "Unable to read image data (unsupported format?)"; return false; } // Get image palette if it exists RGBQUAD* bm_pal = FreeImage_GetPalette(bm); Palette palette; if (bm_pal) { int a = 0; int b = FreeImage_GetColorsUsed(bm); if (b > 256) b = 256; for (; a < b; a++) palette.setColour(a, rgba_t(bm_pal[a].rgbRed, bm_pal[a].rgbGreen, bm_pal[a].rgbBlue, 255)); } // Create image if (info.has_palette) image.create(info, &palette); else image.create(info); uint8_t* img_data = imageData(image); // Convert to 32bpp & flip vertically FIBITMAP* rgba = FreeImage_ConvertTo32Bits(bm); if (!rgba) { LOG_MESSAGE(1, "FreeImage_ConvertTo32Bits failed for image data"); Global::error = "Error reading PNG data"; return false; } FreeImage_FlipVertical(rgba); // Load raw RGBA data uint8_t* bits_rgba = FreeImage_GetBits(rgba); int c = 0; for (int a = 0; a < info.width * info.height; a++) { img_data[c++] = bits_rgba[a * 4 + 2]; // Red img_data[c++] = bits_rgba[a * 4 + 1]; // Green img_data[c++] = bits_rgba[a * 4]; // Blue img_data[c++] = bits_rgba[a * 4 + 3]; // Alpha } // Free memory FreeImage_Unload(rgba); FreeImage_Unload(bm); return true; }
/** @brief Inverts each pixel data. @param src Input image to be processed. @return Returns TRUE if successful, FALSE otherwise. */ BOOL DLL_CALLCONV FreeImage_Invert(FIBITMAP *src) { unsigned i, x, y, k; BYTE *bits; if (!src) return FALSE; int bpp = FreeImage_GetBPP(src); switch(bpp) { case 1 : case 4 : case 8 : { // if the dib has a colormap, just invert it // else, keep the linear grayscale if (FreeImage_GetColorType(src) == FIC_PALETTE) { RGBQUAD *pal = FreeImage_GetPalette(src); for(i = 0; i < FreeImage_GetColorsUsed(src); i++) { pal[i].rgbRed = 255 - pal[i].rgbRed; pal[i].rgbGreen = 255 - pal[i].rgbGreen; pal[i].rgbBlue = 255 - pal[i].rgbBlue; } } else { for(y = 0; y < FreeImage_GetHeight(src); y++) { bits = FreeImage_GetScanLine(src, y); for (x = 0; x < FreeImage_GetLine(src); x++) { bits[x] = ~bits[x]; } } } break; } case 24 : case 32 : { unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src); for(y = 0; y < FreeImage_GetHeight(src); y++) { bits = FreeImage_GetScanLine(src, y); for(x = 0; x < FreeImage_GetWidth(src); x++) { for(k = 0; k < bytespp; k++) { bits[k] = ~bits[k]; } bits += bytespp; } } break; } } return TRUE; }
HANDLE fipWinImage::copyToHandle() const { HANDLE hMem = NULL; if(_dib) { // Get equivalent DIB size long dib_size = sizeof(BITMAPINFOHEADER); dib_size += FreeImage_GetColorsUsed(_dib) * sizeof(RGBQUAD); dib_size += FreeImage_GetPitch(_dib) * FreeImage_GetHeight(_dib); // Allocate a DIB hMem = GlobalAlloc(GHND, dib_size); BYTE *dib = (BYTE*)GlobalLock(hMem); memset(dib, 0, dib_size); BYTE *p_dib = (BYTE*)dib; // Copy the BITMAPINFOHEADER BITMAPINFOHEADER *bih = FreeImage_GetInfoHeader(_dib); memcpy(p_dib, bih, sizeof(BITMAPINFOHEADER)); if(FreeImage_GetImageType(_dib) != FIT_BITMAP) { // this hack is used to store the bitmap type in the biCompression member of the BITMAPINFOHEADER SET_FREEIMAGE_MARKER((BITMAPINFOHEADER*)p_dib, _dib); } p_dib += sizeof(BITMAPINFOHEADER); // Copy the palette RGBQUAD *pal = FreeImage_GetPalette(_dib); memcpy(p_dib, pal, FreeImage_GetColorsUsed(_dib) * sizeof(RGBQUAD)); p_dib += FreeImage_GetColorsUsed(_dib) * sizeof(RGBQUAD); // Copy the bitmap BYTE *bits = FreeImage_GetBits(_dib); memcpy(p_dib, bits, FreeImage_GetPitch(_dib) * FreeImage_GetHeight(_dib)); GlobalUnlock(hMem); } return hMem; }
const QVector<QRgb> ImageLoaderFreeImage::colorTable() const { QVector<QRgb> result; const RGBQUAD* const palette = FreeImage_GetPalette(m_bitmap); if (palette) { const int count = FreeImage_GetColorsUsed(m_bitmap); result.resize(count); for (int i = 0; i < count; i++) result.replace(i, qRgb(palette[i].rgbRed, palette[i].rgbGreen, palette[i].rgbBlue)); } return result; }
/** @brief Sets the index of the palette entry to be used as transparent color for the image specified. Does nothing on high color images. This method sets the index of the palette entry to be used as single transparent color for the image specified. This works on palletised images only and does nothing for high color images. Although it is possible for palletised images to have more than one transparent color, this method sets the palette entry specified as the single transparent color for the image. All other colors will be set to be non-transparent by this method. As with FreeImage_SetTransparencyTable(), this method also sets the image's transparency property to TRUE (as it is set and obtained by FreeImage_SetTransparent() and FreeImage_IsTransparent() respectively) for palletised images. @param dib Input image, whose transparent color is to be set. @param index The index of the palette entry to be set as transparent color. */ void DLL_CALLCONV FreeImage_SetTransparentIndex(FIBITMAP *dib, int index) { if (dib) { int count = FreeImage_GetColorsUsed(dib); if (count) { BYTE *new_tt = (BYTE *)malloc(count * sizeof(BYTE)); memset(new_tt, 0xFF, count); if ((index >= 0) && (index < count)) { new_tt[index] = 0x00; } FreeImage_SetTransparencyTable(dib, new_tt, count); free(new_tt); } } }
BYTE * DLL_CALLCONV FreeImage_GetBits(FIBITMAP *dib) { if(!FreeImage_HasPixels(dib)) { return NULL; } if(((FREEIMAGEHEADER *)dib->data)->external_bits) { return ((FREEIMAGEHEADER *)dib->data)->external_bits; } // returns the pixels aligned on a FIBITMAP_ALIGNMENT bytes alignment boundary size_t lp = (size_t)FreeImage_GetInfoHeader(dib); lp += sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * FreeImage_GetColorsUsed(dib); lp += FreeImage_HasRGBMasks(dib) ? sizeof(DWORD) * 3 : 0; lp += (lp % FIBITMAP_ALIGNMENT ? FIBITMAP_ALIGNMENT - lp % FIBITMAP_ALIGNMENT : 0); return (BYTE *)lp; }
BOOL fipWinImage::copyFromBitmap(HBITMAP hbmp) { if(hbmp) { int Success; BITMAP bm; // Get informations about the bitmap GetObject(hbmp, sizeof(BITMAP), (LPSTR) &bm); // Create the image setSize(FIT_BITMAP, (WORD)bm.bmWidth, (WORD)bm.bmHeight, (WORD)bm.bmBitsPixel); // The GetDIBits function clears the biClrUsed and biClrImportant BITMAPINFO members (dont't know why) // So we save these infos below. This is needed for palettized images only. int nColors = FreeImage_GetColorsUsed(_dib); // Create a device context for the bitmap HDC dc = GetDC(NULL); // Copy the pixels Success = GetDIBits(dc, // handle to DC hbmp, // handle to bitmap 0, // first scan line to set FreeImage_GetHeight(_dib), // number of scan lines to copy FreeImage_GetBits(_dib), // array for bitmap bits FreeImage_GetInfo(_dib), // bitmap data buffer DIB_RGB_COLORS // RGB ); if(Success == 0) { FreeImage_OutputMessageProc(FIF_UNKNOWN, "Error : GetDIBits failed"); ReleaseDC(NULL, dc); return FALSE; } ReleaseDC(NULL, dc); // restore BITMAPINFO members FreeImage_GetInfoHeader(_dib)->biClrUsed = nColors; FreeImage_GetInfoHeader(_dib)->biClrImportant = nColors; return TRUE; } return FALSE; }
/** @brief Determines, whether a palletized image is visually greyscale or not. Unlike with FreeImage_GetColorType, which returns either FIC_MINISBLACK or FIC_MINISWHITE for a greyscale image with a linear ramp palette, the return value of this function does not depend on the palette's order, but only on the palette's individual colors. @param dib The image to be tested. @return Returns TRUE if the palette of the image specified contains only greyscales, FALSE otherwise. */ static BOOL IsVisualGreyscaleImage(FIBITMAP *dib) { switch (FreeImage_GetBPP(dib)) { case 1: case 4: case 8: { unsigned ncolors = FreeImage_GetColorsUsed(dib); RGBQUAD *rgb = FreeImage_GetPalette(dib); for (unsigned i = 0; i< ncolors; i++) { if ((rgb->rgbRed != rgb->rgbGreen) || (rgb->rgbRed != rgb->rgbBlue)) { return FALSE; } } return TRUE; } default: { return (FreeImage_GetColorType(dib) == FIC_MINISBLACK); } } }
static FIBITMAP *FreeImage_CreateDIBFromHBITMAP(HBITMAP hBmp) { BITMAP bm; if(hBmp) { GetObject(hBmp, sizeof(BITMAP), (LPSTR) &bm); FIBITMAP *dib = FreeImage_Allocate(bm.bmWidth, bm.bmHeight, bm.bmBitsPixel,0,0,0); // The GetDIBits function clears the biClrUsed and biClrImportant BITMAPINFO members (dont't know why) // So we save these infos below. This is needed for palettized images only. int nColors = FreeImage_GetColorsUsed(dib); HDC dc = GetDC(NULL); int Success = GetDIBits(dc, hBmp, 0, FreeImage_GetHeight(dib), FreeImage_GetBits(dib), FreeImage_GetInfo(dib), DIB_RGB_COLORS); ReleaseDC(NULL, dc); // restore BITMAPINFO members FreeImage_GetInfoHeader(dib)->biClrUsed = nColors; FreeImage_GetInfoHeader(dib)->biClrImportant = nColors; return dib; } return NULL; }
FIBITMAP* getFIInfo(MemChunk& data, SImage::info_t& info) { // Get FreeImage bitmap info from entry data FIMEMORY* mem = FreeImage_OpenMemory((BYTE*)data.getData(), data.getSize()); FREE_IMAGE_FORMAT fif = FreeImage_GetFileTypeFromMemory(mem, 0); FIBITMAP* bm = FreeImage_LoadFromMemory(fif, mem, 0); FreeImage_CloseMemory(mem); // Check it created/read ok if (!bm) return nullptr; // Get info from image info.width = FreeImage_GetWidth(bm); info.height = FreeImage_GetHeight(bm); info.colformat = RGBA; // Generic images always converted to RGBA on loading info.format = id_; // Check if palette supplied if (FreeImage_GetColorsUsed(bm) > 0) info.has_palette = true; return bm; }
static BOOL DLL_CALLCONV Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { if ((dib != NULL) && (handle != NULL)) { // write the file header BITMAPFILEHEADER bitmapfileheader; bitmapfileheader.bfType = 0x4D42; bitmapfileheader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + FreeImage_GetHeight(dib) * FreeImage_GetPitch(dib); bitmapfileheader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD); bitmapfileheader.bfReserved1 = 0; bitmapfileheader.bfReserved2 = 0; // take care of the bit fields data of any bool bit_fields = (FreeImage_GetBPP(dib) == 16); if (bit_fields) { bitmapfileheader.bfSize += 3 * sizeof(DWORD); bitmapfileheader.bfOffBits += 3 * sizeof(DWORD); } #ifdef FREEIMAGE_BIGENDIAN SwapFileHeader(&bitmapfileheader); #endif if (io->write_proc(&bitmapfileheader, sizeof(BITMAPFILEHEADER), 1, handle) != 1) return FALSE; // update the bitmap info header BITMAPINFOHEADER bih = *FreeImage_GetInfoHeader(dib); if (bit_fields) bih.biCompression = BI_BITFIELDS; else if ((bih.biBitCount == 8) && (flags & BMP_SAVE_RLE)) bih.biCompression = BI_RLE8; else bih.biCompression = BI_RGB; // write the bitmap info header #ifdef FREEIMAGE_BIGENDIAN SwapInfoHeader(&bih); #endif if (io->write_proc(&bih, sizeof(BITMAPINFOHEADER), 1, handle) != 1) return FALSE; // write the bit fields when we are dealing with a 16 bit BMP if (bit_fields) { DWORD d; d = FreeImage_GetRedMask(dib); if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1) return FALSE; d = FreeImage_GetGreenMask(dib); if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1) return FALSE; d = FreeImage_GetBlueMask(dib); if (io->write_proc(&d, sizeof(DWORD), 1, handle) != 1) return FALSE; } // write the palette if (FreeImage_GetPalette(dib) != NULL) { RGBQUAD *pal = FreeImage_GetPalette(dib); FILE_BGRA bgra; for(unsigned i = 0; i < FreeImage_GetColorsUsed(dib); i++ ) { bgra.b = pal[i].rgbBlue; bgra.g = pal[i].rgbGreen; bgra.r = pal[i].rgbRed; bgra.a = pal[i].rgbReserved; if (io->write_proc(&bgra, sizeof(FILE_BGRA), 1, handle) != 1) return FALSE; } } // write the bitmap data... if RLE compression is enable, use it unsigned bpp = FreeImage_GetBPP(dib); if ((bpp == 8) && (flags & BMP_SAVE_RLE)) { BYTE *buffer = new BYTE[FreeImage_GetPitch(dib) * 2]; for (DWORD i = 0; i < FreeImage_GetHeight(dib); ++i) { int size = RLEEncodeLine(buffer, FreeImage_GetScanLine(dib, i), FreeImage_GetLine(dib)); if (io->write_proc(buffer, size, 1, handle) != 1) { delete [] buffer; return FALSE; } } buffer[0] = RLE_COMMAND; buffer[1] = RLE_ENDOFBITMAP; if (io->write_proc(buffer, 2, 1, handle) != 1) { delete [] buffer; return FALSE; } delete [] buffer; #ifdef FREEIMAGE_BIGENDIAN } else if (bpp == 16) { WORD pixel; for(int y = 0; y < FreeImage_GetHeight(dib); y++) { BYTE *line = FreeImage_GetScanLine(dib, y); for(int x = 0; x < FreeImage_GetWidth(dib); x++) { pixel = ((WORD *)line)[x]; SwapShort(&pixel); if (io->write_proc(&pixel, sizeof(WORD), 1, handle) != 1) return FALSE; } } } else if (bpp == 24) { FILE_BGR bgr; for(int y = 0; y < FreeImage_GetHeight(dib); y++) { BYTE *line = FreeImage_GetScanLine(dib, y); for(int x = 0; x < FreeImage_GetWidth(dib); x++) { RGBTRIPLE *triple = ((RGBTRIPLE *)line)+x; bgr.b = triple->rgbtBlue; bgr.g = triple->rgbtGreen; bgr.r = triple->rgbtRed; if (io->write_proc(&bgr, sizeof(FILE_BGR), 1, handle) != 1) return FALSE; } } } else if (bpp == 32) { FILE_BGRA bgra; for(int y = 0; y < FreeImage_GetHeight(dib); y++) { BYTE *line = FreeImage_GetScanLine(dib, y); for(int x = 0; x < FreeImage_GetWidth(dib); x++) { RGBQUAD *quad = ((RGBQUAD *)line)+x; bgra.b = quad->rgbBlue; bgra.g = quad->rgbGreen; bgra.r = quad->rgbRed; bgra.a = quad->rgbReserved; if (io->write_proc(&bgra, sizeof(FILE_BGRA), 1, handle) != 1) return FALSE; } } #endif } else if (io->write_proc(FreeImage_GetBits(dib), FreeImage_GetHeight(dib) * FreeImage_GetPitch(dib), 1, handle) != 1) { return FALSE; } return TRUE; } else { return FALSE; } }
/** @brief Allocates a new image of the specified type, width, height and bit depth and optionally fills it with the specified color. This function is an extension to FreeImage_AllocateT, which additionally supports specifying a palette to be set for the newly create image, as well as specifying a background color, the newly created image should initially be filled with. Basically, this function internally relies on function FreeImage_AllocateT, followed by a call to FreeImage_FillBackground. This is why both parameters color and options behave the same as it is documented for function FreeImage_FillBackground. So, please refer to the documentation of FreeImage_FillBackground to learn more about parameters color and options. The palette specified through parameter palette is only copied to the newly created image, if its image type is FIT_BITMAP and the desired bit depth is smaller than or equal to 8 bits per pixel. In other words, the palette parameter is only taken into account for palletized images. However, if the preceding conditions match and if palette is not NULL, the memory pointed to by the palette pointer is assumed to be at least as large as size of a fully populated palette for the desired bit depth. So, for an 8-bit image, this size is 256 x sizeof(RGBQUAD), for an 4-bit image it is 16 x sizeof(RGBQUAD) and it is 2 x sizeof(RGBQUAD) for a 1-bit image. In other words, this function does not support partial palettes. However, specifying a palette is not necessarily needed, even for palletized images. This function is capable of implicitly creating a palette, if parameter palette is NULL. If the specified background color is a greyscale value (red = green = blue) or if option FI_COLOR_ALPHA_IS_INDEX is specified, a greyscale palette is created. For a 1-bit image, only if the specified background color is either black or white, a monochrome palette, consisting of black and white only is created. In any case, the darker colors are stored at the smaller palette indices. If the specified background color is not a greyscale value, or is neither black nor white for a 1-bit image, solely this single color is injected into the otherwise black-initialized palette. For this operation, option FI_COLOR_ALPHA_IS_INDEX is implicit, so the specified color is applied to the palette entry, specified by the background color's rgbReserved member. The image is then filled with this palette index. This function returns a newly created image as function FreeImage_AllocateT does, if both parameters color and palette are NULL. If only color is NULL, the palette pointed to by parameter palette is initially set for the new image, if a palletized image of type FIT_BITMAP is created. However, in the latter case, this function returns an image, whose pixels are all initialized with zeros so, the image will be filled with the color of the first palette entry. @param type Specifies the image type of the new image. @param width The desired width in pixels of the new image. @param height The desired height in pixels of the new image. @param bpp The desired bit depth of the new image. @param color A pointer to the color value to be used for filling the image. The memory pointed to by this pointer is always assumed to be at least as large as the image's color value but never smaller than the size of an RGBQUAD structure. @param options Options that affect the color search process for palletized images. @param red_mask Specifies the bits used to store the red components of a pixel. @param green_mask Specifies the bits used to store the green components of a pixel. @param blue_mask Specifies the bits used to store the blue components of a pixel. @return Returns a pointer to a newly allocated image on success, NULL otherwise. */ FIBITMAP * DLL_CALLCONV FreeImage_AllocateExT(FREE_IMAGE_TYPE type, int width, int height, int bpp, const void *color, int options, const RGBQUAD *palette, unsigned red_mask, unsigned green_mask, unsigned blue_mask) { FIBITMAP *bitmap = FreeImage_AllocateT(type, width, height, bpp, red_mask, green_mask, blue_mask); if (!color) { if ((palette) && (type == FIT_BITMAP) && (bpp <= 8)) { memcpy(FreeImage_GetPalette(bitmap), palette, FreeImage_GetColorsUsed(bitmap) * sizeof(RGBQUAD)); } return bitmap; } if (bitmap != NULL) { // Only fill the new bitmap if the specified color // differs from "black", that is not all bytes of the // color are equal to zero. switch (bpp) { case 1: { // although 1-bit implies FIT_BITMAP, better get an unsigned // color and palette unsigned *urgb = (unsigned *)color; unsigned *upal = (unsigned *)FreeImage_GetPalette(bitmap); RGBQUAD rgbq = RGBQUAD(); if (palette != NULL) { // clone the specified palette memcpy(FreeImage_GetPalette(bitmap), palette, 2 * sizeof(RGBQUAD)); } else if (options & FI_COLOR_ALPHA_IS_INDEX) { CREATE_GREYSCALE_PALETTE(upal, 2); } else { // check, whether the specified color is either black or white if ((*urgb & 0xFFFFFF) == 0x000000) { // in any case build a FIC_MINISBLACK palette CREATE_GREYSCALE_PALETTE(upal, 2); color = &rgbq; } else if ((*urgb & 0xFFFFFF) == 0xFFFFFF) { // in any case build a FIC_MINISBLACK palette CREATE_GREYSCALE_PALETTE(upal, 2); rgbq.rgbReserved = 1; color = &rgbq; } else { // Otherwise inject the specified color into the so far // black-only palette. We use color->rgbReserved as the // desired palette index. BYTE index = ((RGBQUAD *)color)->rgbReserved & 0x01; upal[index] = *urgb & 0x00FFFFFF; } options |= FI_COLOR_ALPHA_IS_INDEX; } // and defer to FreeImage_FillBackground FreeImage_FillBackground(bitmap, color, options); break; } case 4: { // 4-bit implies FIT_BITMAP so, get a RGBQUAD color RGBQUAD *rgb = (RGBQUAD *)color; RGBQUAD *pal = FreeImage_GetPalette(bitmap); RGBQUAD rgbq = RGBQUAD(); if (palette != NULL) { // clone the specified palette memcpy(pal, palette, 16 * sizeof(RGBQUAD)); } else if (options & FI_COLOR_ALPHA_IS_INDEX) { CREATE_GREYSCALE_PALETTE(pal, 16); } else { // check, whether the specified color is a grey one if ((rgb->rgbRed == rgb->rgbGreen) && (rgb->rgbRed == rgb->rgbBlue)) { // if so, build a greyscale palette CREATE_GREYSCALE_PALETTE(pal, 16); rgbq.rgbReserved = rgb->rgbRed >> 4; color = &rgbq; } else { // Otherwise inject the specified color into the so far // black-only palette. We use color->rgbReserved as the // desired palette index. BYTE index = (rgb->rgbReserved & 0x0F); ((unsigned *)pal)[index] = *((unsigned *)rgb) & 0x00FFFFFF; } options |= FI_COLOR_ALPHA_IS_INDEX; } // and defer to FreeImage_FillBackground FreeImage_FillBackground(bitmap, color, options); break; } case 8: { // 8-bit implies FIT_BITMAP so, get a RGBQUAD color RGBQUAD *rgb = (RGBQUAD *)color; RGBQUAD *pal = FreeImage_GetPalette(bitmap); RGBQUAD rgbq; if (palette != NULL) { // clone the specified palette memcpy(pal, palette, 256 * sizeof(RGBQUAD)); } else if (options & FI_COLOR_ALPHA_IS_INDEX) { CREATE_GREYSCALE_PALETTE(pal, 256); } else { // check, whether the specified color is a grey one if ((rgb->rgbRed == rgb->rgbGreen) && (rgb->rgbRed == rgb->rgbBlue)) { // if so, build a greyscale palette CREATE_GREYSCALE_PALETTE(pal, 256); rgbq.rgbReserved = rgb->rgbRed; color = &rgbq; } else { // Otherwise inject the specified color into the so far // black-only palette. We use color->rgbReserved as the // desired palette index. BYTE index = rgb->rgbReserved; ((unsigned *)pal)[index] = *((unsigned *)rgb) & 0x00FFFFFF; } options |= FI_COLOR_ALPHA_IS_INDEX; } // and defer to FreeImage_FillBackground FreeImage_FillBackground(bitmap, color, options); break; } case 16: { WORD wcolor = (type == FIT_BITMAP) ? RGBQUAD_TO_WORD(bitmap, ((RGBQUAD *)color)) : *((WORD *)color); if (wcolor != 0) { FreeImage_FillBackground(bitmap, color, options); } break; } default: { int bytespp = bpp / 8; for (int i = 0; i < bytespp; i++) { if (((BYTE *)color)[i] != 0) { FreeImage_FillBackground(bitmap, color, options); break; } } break; } }
unsigned DLL_CALLCONV FreeImage_GetDIBSize(FIBITMAP *dib) { return (dib) ? sizeof(BITMAPINFOHEADER) + (FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD)) + (FreeImage_GetPitch(dib) * FreeImage_GetHeight(dib)) : 0; }
static FIBITMAP * DLL_CALLCONV Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) { if (handle != NULL) { FIBITMAP *dib = NULL; DWORD type, size; io->read_proc(&type, 4, 1, handle); #ifndef FREEIMAGE_BIGENDIAN SwapLong(&type); #endif if(type != ID_FORM) return NULL; io->read_proc(&size, 4, 1, handle); #ifndef FREEIMAGE_BIGENDIAN SwapLong(&size); #endif io->read_proc(&type, 4, 1, handle); #ifndef FREEIMAGE_BIGENDIAN SwapLong(&type); #endif if((type != ID_ILBM) && (type != ID_PBM)) return NULL; size -= 4; unsigned width = 0, height = 0, planes = 0, depth = 0, comp = 0; while (size) { DWORD ch_type,ch_size; io->read_proc(&ch_type, 4, 1, handle); #ifndef FREEIMAGE_BIGENDIAN SwapLong(&ch_type); #endif io->read_proc(&ch_size,4,1,handle ); #ifndef FREEIMAGE_BIGENDIAN SwapLong(&ch_size); #endif unsigned ch_end = io->tell_proc(handle) + ch_size; if (ch_type == ID_BMHD) { // Bitmap Header if (dib) FreeImage_Unload(dib); BMHD bmhd; io->read_proc(&bmhd, sizeof(bmhd), 1, handle); #ifndef FREEIMAGE_BIGENDIAN SwapHeader(&bmhd); #endif width = bmhd.w; height = bmhd.h; planes = bmhd.nPlanes; comp = bmhd.compression; if(bmhd.masking & 1) planes++; // there is a mask ( 'stencil' ) if (planes > 8 && planes != 24) return NULL; depth = planes > 8 ? 24 : 8; if( depth == 24 ) { dib = FreeImage_Allocate(width, height, depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); } else { dib = FreeImage_Allocate(width, height, depth); } } else if (ch_type == ID_CMAP) { // Palette (Color Map) if (!dib) return NULL; RGBQUAD *pal = FreeImage_GetPalette(dib); if(pal != NULL) { unsigned palette_entries = MIN((unsigned)ch_size / 3, FreeImage_GetColorsUsed(dib)); for (unsigned k = 0; k < palette_entries; k++) { io->read_proc(&pal[k].rgbRed, 1, 1, handle ); io->read_proc(&pal[k].rgbGreen, 1, 1, handle ); io->read_proc(&pal[k].rgbBlue, 1, 1, handle ); } } } else if (ch_type == ID_BODY) { if (!dib) return NULL; if (type == ID_PBM) { // NON INTERLACED (LBM) unsigned line = FreeImage_GetLine(dib) + 1 & ~1; for (unsigned i = 0; i < FreeImage_GetHeight(dib); i++) { BYTE *bits = FreeImage_GetScanLine(dib, FreeImage_GetHeight(dib) - i - 1); if (comp == 1) { // use RLE compression DWORD number_of_bytes_written = 0; BYTE rle_count; BYTE byte; while (number_of_bytes_written < line) { io->read_proc(&rle_count, 1, 1, handle); if (rle_count < 128) { for (int k = 0; k < rle_count + 1; k++) { io->read_proc(&byte, 1, 1, handle); bits[number_of_bytes_written++] += byte; } } else if (rle_count > 128) { io->read_proc(&byte, 1, 1, handle); for (int k = 0; k < 257 - rle_count; k++) { bits[number_of_bytes_written++] += byte; } } } } else { // don't use compression io->read_proc(bits, line, 1, handle); } } return dib; } else { // INTERLACED (ILBM) unsigned pixel_size = depth/8; unsigned n_width=(width+15)&~15; unsigned plane_size = n_width/8; unsigned src_size = plane_size * planes; BYTE *src = (BYTE*)malloc(src_size); BYTE *dest = FreeImage_GetBits(dib); dest += FreeImage_GetPitch(dib) * height; for (unsigned y = 0; y < height; y++) { dest -= FreeImage_GetPitch(dib); // read all planes in one hit, // 'coz PSP compresses across planes... if (comp) { // unpacker algorithm for(unsigned x = 0; x < src_size;) { // read the next source byte into t signed char t = 0; io->read_proc(&t, 1, 1, handle); if (t >= 0) { // t = [0..127] => copy the next t+1 bytes literally unsigned size_to_read = t + 1; if((size_to_read + x) > src_size) { // sanity check for buffer overruns size_to_read = src_size - x; io->read_proc(src + x, size_to_read, 1, handle); x += (t + 1); } else { io->read_proc(src + x, size_to_read, 1, handle); x += size_to_read; } } else if (t != -128) { // t = [-1..-127] => replicate the next byte -t+1 times BYTE b = 0; io->read_proc(&b, 1, 1, handle); unsigned size_to_copy = (unsigned)(-(int)t + 1); if((size_to_copy + x) > src_size) { // sanity check for buffer overruns size_to_copy = src_size - x; memset(src + x, b, size_to_copy); x += (unsigned)(-(int)t + 1); } else { memset(src + x, b, size_to_copy); x += size_to_copy; } } // t = -128 => noop } } else { io->read_proc(src, src_size, 1, handle); } // lazy planar->chunky... for (unsigned x = 0; x < width; x++) { for (unsigned n = 0; n < planes; n++) { BYTE bit = (BYTE)( src[n * plane_size + (x / 8)] >> ((x^7) & 7) ); dest[x * pixel_size + (n / 8)] |= (bit & 1) << (n & 7); } } #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR if (depth == 24) { for (unsigned x = 0; x < width; ++x){ INPLACESWAP(dest[x * 3], dest[x * 3 + 2]); } } #endif } free(src); return dib; } } // Every odd-length chunk is followed by a 0 pad byte. This pad // byte is not counted in ch_size. if (ch_size & 1) { ch_size++; ch_end++; } io->seek_proc(handle, ch_end - io->tell_proc(handle), SEEK_CUR); size -= ch_size + 8; } if (dib) FreeImage_Unload(dib); }
FREE_IMAGE_COLOR_TYPE DLL_CALLCONV FreeImage_GetColorType(FIBITMAP *dib) { RGBQUAD *rgb; FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); // special bitmap type if(image_type != FIT_BITMAP) { switch(image_type) { case FIT_RGB16: case FIT_RGBF: return FIC_RGB; case FIT_RGBA16: case FIT_RGBAF: return FIC_RGBALPHA; } return FIC_MINISBLACK; } // standard image type switch (FreeImage_GetBPP(dib)) { case 1: { rgb = FreeImage_GetPalette(dib); if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) { rgb++; if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) return FIC_MINISBLACK; } if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) { rgb++; if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) return FIC_MINISWHITE; } return FIC_PALETTE; } case 4: case 8: // Check if the DIB has a color or a greyscale palette { int ncolors = FreeImage_GetColorsUsed(dib); int minisblack = 1; rgb = FreeImage_GetPalette(dib); for (int i = 0; i < ncolors; i++) { if ((rgb->rgbRed != rgb->rgbGreen) || (rgb->rgbRed != rgb->rgbBlue)) return FIC_PALETTE; // The DIB has a color palette if the greyscale isn't a linear ramp // Take care of reversed grey images if (rgb->rgbRed != i) { if ((ncolors-i-1) != rgb->rgbRed) return FIC_PALETTE; else minisblack = 0; } rgb++; } return minisblack ? FIC_MINISBLACK : FIC_MINISWHITE; } case 16: case 24: return FIC_RGB; case 32: { if (FreeImage_GetICCProfile(dib)->flags & FIICC_COLOR_IS_CMYK) return FIC_CMYK; for (unsigned y = 0; y < FreeImage_GetHeight(dib); y++) { rgb = (RGBQUAD *)FreeImage_GetScanLine(dib, y); for (unsigned x = 0; x < FreeImage_GetWidth(dib); x++) if (rgb[x].rgbReserved != 0xFF) return FIC_RGBALPHA; } return FIC_RGB; } default : return FIC_MINISBLACK; } }
static HBITMAP GetDibSection(FIBITMAP *src, HDC hdc, int left, int top, int right, int bottom) { if(!src) return NULL; unsigned bpp = FreeImage_GetBPP(src); if(bpp <=4) return NULL; // normalize the rectangle if(right < left) INPLACESWAP(left, right); if(bottom < top) INPLACESWAP(top, bottom); // check the size of the sub image int src_width = FreeImage_GetWidth(src); int src_height = FreeImage_GetHeight(src); int src_pitch = FreeImage_GetPitch(src); if((left < 0) || (right > src_width) || (top < 0) || (bottom > src_height)) return NULL; // allocate the sub image int dst_width = (right - left); int dst_height = (bottom - top); BITMAPINFO *info = (BITMAPINFO *) malloc(sizeof(BITMAPINFO) + (FreeImage_GetColorsUsed(src) * sizeof(RGBQUAD))); BITMAPINFOHEADER *bih = (BITMAPINFOHEADER *)info; bih->biSize = sizeof(BITMAPINFOHEADER); bih->biWidth = dst_width; bih->biHeight = dst_height; bih->biPlanes = 1; bih->biBitCount = bpp; bih->biCompression = BI_RGB; bih->biSizeImage = 0; bih->biXPelsPerMeter = 0; bih->biYPelsPerMeter = 0; bih->biClrUsed = 0; // Always use the whole palette. bih->biClrImportant = 0; // copy the palette if(bpp < 16) memcpy(info->bmiColors, FreeImage_GetPalette(src), FreeImage_GetColorsUsed(src) * sizeof(RGBQUAD)); BYTE *dst_bits; HBITMAP hbitmap = CreateDIBSection(hdc, info, DIB_RGB_COLORS, (void **) &dst_bits, NULL, 0); free(info); if(hbitmap == NULL || dst_bits == NULL) return NULL; // get the pointers to the bits and such BYTE *src_bits = FreeImage_GetScanLine(src, src_height - top - dst_height); // calculate the number of bytes per pixel unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src); // point to x = left src_bits += (left * bytespp); int dst_line = (dst_width * bpp + 7) / 8; int dst_pitch = (dst_line + 3) & ~3; for(int y = 0; y < dst_height; y++) memcpy(dst_bits + (y * dst_pitch), src_bits + (y * src_pitch), dst_line); return hbitmap; }
/** @brief Looks up a specified color in a FIBITMAP's palette and returns the color's palette index or -1 if the color was not found. Unlike with FreeImage_GetColorType, which returns either FIC_MINISBLACK or FIC_MINISWHITE for a greyscale image with a linear ramp palette, the return value of this function does not depend on the palette's order, but only on the palette's individual colors. @param dib The image, whose palette should be searched through. @param color The color to be searched in the palette. @param options Options that affect the color search process. @param color_type A pointer, that optionally specifies the image's color type as returned by FreeImage_GetColorType. If invalid or NULL, this function determines the color type with FreeImage_GetColorType. @return Returns the specified color's palette index, the color's rgbReserved member if option FI_COLOR_ALPHA_IS_INDEX was specified or -1, if the color was not found in the image's palette or if the specified image is non-palletized. */ static int GetPaletteIndex(FIBITMAP *dib, const RGBQUAD *color, int options, FREE_IMAGE_COLOR_TYPE *color_type) { int result = -1; if ((!dib) || (!color)) { return result; } int bpp = FreeImage_GetBPP(dib); // First check trivial case: return color->rgbReserved if only // FI_COLOR_ALPHA_IS_INDEX is set. if ((options & FI_COLOR_ALPHA_IS_INDEX) == FI_COLOR_ALPHA_IS_INDEX) { if (bpp == 1) { return color->rgbReserved & 0x01; } else if (bpp == 4) { return color->rgbReserved & 0x0F; } return color->rgbReserved; } if (bpp == 8) { FREE_IMAGE_COLOR_TYPE ct = (color_type == NULL || *color_type < 0) ? FreeImage_GetColorType(dib) : *color_type; if (ct == FIC_MINISBLACK) { return GREY(color->rgbRed, color->rgbGreen, color->rgbBlue); } if (ct == FIC_MINISWHITE) { return 255 - GREY(color->rgbRed, color->rgbGreen, color->rgbBlue); } } else if (bpp > 8) { // for palettized images only return result; } if (options & FI_COLOR_FIND_EQUAL_COLOR) { // Option FI_COLOR_ALPHA_IS_INDEX is implicit here so, set // index to color->rgbReserved result = color->rgbReserved; if (bpp == 1) { result &= 0x01; } else if (bpp == 4) { result &= 0x0F; } unsigned ucolor; if (!IsVisualGreyscaleImage(dib)) { ucolor = (*((unsigned *)color)) & 0xFFFFFF; } else { ucolor = GREY(color->rgbRed, color->rgbGreen, color->rgbBlue) * 0x010101; //ucolor = (ucolor | (ucolor << 8) | (ucolor << 16)); } unsigned ncolors = FreeImage_GetColorsUsed(dib); unsigned *palette = (unsigned *)FreeImage_GetPalette(dib); for (unsigned i = 0; i < ncolors; i++) { if ((palette[i] & 0xFFFFFF) == ucolor) { result = i; break; } } } else { unsigned minimum = UINT_MAX; unsigned ncolors = FreeImage_GetColorsUsed(dib); BYTE *palette = (BYTE *)FreeImage_GetPalette(dib); BYTE red, green, blue; if (!IsVisualGreyscaleImage(dib)) { red = color->rgbRed; green = color->rgbGreen; blue = color->rgbBlue; } else { red = GREY(color->rgbRed, color->rgbGreen, color->rgbBlue); green = blue = red; } for (unsigned i = 0; i < ncolors; i++) { unsigned m = abs(palette[FI_RGBA_BLUE] - blue) + abs(palette[FI_RGBA_GREEN] - green) + abs(palette[FI_RGBA_RED] - red); if (m < minimum) { minimum = m; result = i; if (m == 0) { break; } } palette += sizeof(RGBQUAD); } } return result; }
/** @brief Perfoms an histogram transformation on a 8, 24 or 32-bit image according to the values of a lookup table (LUT). The transformation is done as follows.<br> Image 8-bit : if the image has a color palette, the LUT is applied to this palette, otherwise, it is applied to the grey values.<br> Image 24-bit & 32-bit : if channel == FICC_RGB, the same LUT is applied to each color plane (R,G, and B). Otherwise, the LUT is applied to the specified channel only. @param src Input image to be processed. @param LUT Lookup table. <b>The size of 'LUT' is assumed to be 256.</b> @param channel The color channel to be processed (only used with 24 & 32-bit DIB). @return Returns TRUE if successful, FALSE otherwise. @see FREE_IMAGE_COLOR_CHANNEL */ BOOL DLL_CALLCONV FreeImage_AdjustCurve(FIBITMAP *src, BYTE *LUT, FREE_IMAGE_COLOR_CHANNEL channel) { unsigned x, y; BYTE *bits = NULL; if(!src || !LUT || (FreeImage_GetImageType(src) != FIT_BITMAP)) return FALSE; int bpp = FreeImage_GetBPP(src); if((bpp != 8) && (bpp != 24) && (bpp != 32)) return FALSE; // apply the LUT switch(bpp) { case 8 : { // if the dib has a colormap, apply the LUT to it // else, apply the LUT to pixel values if(FreeImage_GetColorType(src) == FIC_PALETTE) { RGBQUAD *rgb = FreeImage_GetPalette(src); for (unsigned pal = 0; pal < FreeImage_GetColorsUsed(src); pal++) { rgb->rgbRed = LUT[rgb->rgbRed]; rgb->rgbGreen = LUT[rgb->rgbGreen]; rgb->rgbBlue = LUT[rgb->rgbBlue]; rgb++; } } else { for(y = 0; y < FreeImage_GetHeight(src); y++) { bits = FreeImage_GetScanLine(src, y); for(x = 0; x < FreeImage_GetWidth(src); x++) { bits[x] = LUT[ bits[x] ]; } } } break; } case 24 : case 32 : { int bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src); switch(channel) { case FICC_RGB : for(y = 0; y < FreeImage_GetHeight(src); y++) { bits = FreeImage_GetScanLine(src, y); for(x = 0; x < FreeImage_GetWidth(src); x++) { bits[FI_RGBA_BLUE] = LUT[ bits[FI_RGBA_BLUE] ]; // B bits[FI_RGBA_GREEN] = LUT[ bits[FI_RGBA_GREEN] ]; // G bits[FI_RGBA_RED] = LUT[ bits[FI_RGBA_RED] ]; // R bits += bytespp; } } break; case FICC_BLUE : for(y = 0; y < FreeImage_GetHeight(src); y++) { bits = FreeImage_GetScanLine(src, y); for(x = 0; x < FreeImage_GetWidth(src); x++) { bits[FI_RGBA_BLUE] = LUT[ bits[FI_RGBA_BLUE] ]; // B bits += bytespp; } } break; case FICC_GREEN : for(y = 0; y < FreeImage_GetHeight(src); y++) { bits = FreeImage_GetScanLine(src, y); for(x = 0; x < FreeImage_GetWidth(src); x++) { bits[FI_RGBA_GREEN] = LUT[ bits[FI_RGBA_GREEN] ]; // G bits += bytespp; } } break; case FICC_RED : for(y = 0; y < FreeImage_GetHeight(src); y++) { bits = FreeImage_GetScanLine(src, y); for(x = 0; x < FreeImage_GetWidth(src); x++) { bits[FI_RGBA_RED] = LUT[ bits[FI_RGBA_RED] ]; // R bits += bytespp; } } break; case FICC_ALPHA : if(32 == bpp) { for(y = 0; y < FreeImage_GetHeight(src); y++) { bits = FreeImage_GetScanLine(src, y); for(x = 0; x < FreeImage_GetWidth(src); x++) { bits[FI_RGBA_ALPHA] = LUT[ bits[FI_RGBA_ALPHA] ]; // A bits += bytespp; } } } break; default: break; } break; } } return TRUE; }
WORD fipImage::getPaletteSize() const { return FreeImage_GetColorsUsed(_dib) * sizeof(RGBQUAD); }
/** @brief Applies color mapping for one or several colors on a 1-, 4- or 8-bit palletized or a 16-, 24- or 32-bit high color image. This function maps up to <i>count</i> colors specified in <i>srccolors</i> to these specified in <i>dstcolors</i>. Thereby, color <i>srccolors[N]</i>, if found in the image, will be replaced by color <i>dstcolors[N]</i>. If parameter <i>swap</i> is TRUE, additionally all colors specified in <i>dstcolors</i> are also mapped to these specified in <i>srccolors</i>. For high color images, the actual image data will be modified whereas, for palletized images only the palette will be changed.<br> The function returns the number of pixels changed or zero, if no pixels were changed. Both arrays <i>srccolors</i> and <i>dstcolors</i> are assumed not to hold less than <i>count</i> colors.<br> For 16-bit images, all colors specified are transparently converted to their proper 16-bit representation (either in RGB555 or RGB565 format, which is determined by the image's red- green- and blue-mask).<br> <b>Note, that this behaviour is different from what FreeImage_ApplyPaletteIndexMapping() does, which modifies the actual image data on palletized images.</b> @param dib Input/output image to be processed. @param srccolors Array of colors to be used as the mapping source. @param dstcolors Array of colors to be used as the mapping destination. @param count The number of colors to be mapped. This is the size of both <i>srccolors</i> and <i>dstcolors</i>. @param ignore_alpha If TRUE, 32-bit images and colors are treated as 24-bit. @param swap If TRUE, source and destination colors are swapped, that is, each destination color is also mapped to the corresponding source color. @return Returns the total number of pixels changed. */ unsigned DLL_CALLCONV FreeImage_ApplyColorMapping(FIBITMAP *dib, RGBQUAD *srccolors, RGBQUAD *dstcolors, unsigned count, BOOL ignore_alpha, BOOL swap) { unsigned result = 0; if ((!dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP)) { return 0; } // validate parameters if ((!srccolors) || (!dstcolors)|| (count < 1)) { return 0; } int bpp = FreeImage_GetBPP(dib); switch (bpp) { case 1: case 4: case 8: { unsigned size = FreeImage_GetColorsUsed(dib); RGBQUAD *pal = FreeImage_GetPalette(dib); RGBQUAD *a, *b; for (unsigned x = 0; x < size; x++) { for (unsigned j = 0; j < count; j++) { a = srccolors; b = dstcolors; for (int i = (swap ? 0 : 1); i < 2; i++) { if ((pal[x].rgbBlue == a[j].rgbBlue)&&(pal[x].rgbGreen == a[j].rgbGreen) &&(pal[x].rgbRed== a[j].rgbRed)) { pal[x].rgbBlue = b[j].rgbBlue; pal[x].rgbGreen = b[j].rgbGreen; pal[x].rgbRed = b[j].rgbRed; result++; j = count; break; } a = dstcolors; b = srccolors; } } } return result; } case 16: { WORD *src16 = (WORD *)malloc(sizeof(WORD) * count); if (NULL == src16) { return 0; } WORD *dst16 = (WORD *)malloc(sizeof(WORD) * count); if (NULL == dst16) { free(src16); return 0; } for (unsigned j = 0; j < count; j++) { src16[j] = RGBQUAD_TO_WORD(dib, (srccolors + j)); dst16[j] = RGBQUAD_TO_WORD(dib, (dstcolors + j)); } unsigned height = FreeImage_GetHeight(dib); unsigned width = FreeImage_GetWidth(dib); WORD *a, *b; for (unsigned y = 0; y < height; y++) { WORD *bits = (WORD *)FreeImage_GetScanLine(dib, y); for (unsigned x = 0; x < width; x++, bits++) { for (unsigned j = 0; j < count; j++) { a = src16; b = dst16; for (int i = (swap ? 0 : 1); i < 2; i++) { if (*bits == a[j]) { *bits = b[j]; result++; j = count; break; } a = dst16; b = src16; } } } } free(src16); free(dst16); return result; } case 24: { unsigned height = FreeImage_GetHeight(dib); unsigned width = FreeImage_GetWidth(dib); RGBQUAD *a, *b; for (unsigned y = 0; y < height; y++) { BYTE *bits = FreeImage_GetScanLine(dib, y); for (unsigned x = 0; x < width; x++, bits += 3) { for (unsigned j = 0; j < count; j++) { a = srccolors; b = dstcolors; for (int i = (swap ? 0 : 1); i < 2; i++) { if ((bits[FI_RGBA_BLUE] == a[j].rgbBlue) && (bits[FI_RGBA_GREEN] == a[j].rgbGreen) &&(bits[FI_RGBA_RED] == a[j].rgbRed)) { bits[FI_RGBA_BLUE] = b[j].rgbBlue; bits[FI_RGBA_GREEN] = b[j].rgbGreen; bits[FI_RGBA_RED] = b[j].rgbRed; result++; j = count; break; } a = dstcolors; b = srccolors; } } } } return result; } case 32: { unsigned height = FreeImage_GetHeight(dib); unsigned width = FreeImage_GetWidth(dib); RGBQUAD *a, *b; for (unsigned y = 0; y < height; y++) { BYTE *bits = FreeImage_GetScanLine(dib, y); for (unsigned x = 0; x < width; x++, bits += 4) { for (unsigned j = 0; j < count; j++) { a = srccolors; b = dstcolors; for (int i = (swap ? 0 : 1); i < 2; i++) { if ((bits[FI_RGBA_BLUE] == a[j].rgbBlue) &&(bits[FI_RGBA_GREEN] == a[j].rgbGreen) &&(bits[FI_RGBA_RED] == a[j].rgbRed) &&((ignore_alpha) || (bits[FI_RGBA_ALPHA] == a[j].rgbReserved))) { bits[FI_RGBA_BLUE] = b[j].rgbBlue; bits[FI_RGBA_GREEN] = b[j].rgbGreen; bits[FI_RGBA_RED] = b[j].rgbRed; if (!ignore_alpha) { bits[FI_RGBA_ALPHA] = b[j].rgbReserved; } result++; j = count; break; } a = dstcolors; b = srccolors; } } } } return result; } default: { return 0; } } }
/** @brief Inverts each pixel data. @param src Input image to be processed. @return Returns TRUE if successful, FALSE otherwise. */ BOOL DLL_CALLCONV FreeImage_Invert(FIBITMAP *src) { if (!FreeImage_HasPixels(src)) return FALSE; unsigned i, x, y, k; const unsigned width = FreeImage_GetWidth(src); const unsigned height = FreeImage_GetHeight(src); const unsigned bpp = FreeImage_GetBPP(src); FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(src); if(image_type == FIT_BITMAP) { switch(bpp) { case 1 : case 4 : case 8 : { // if the dib has a colormap, just invert it // else, keep the linear grayscale if (FreeImage_GetColorType(src) == FIC_PALETTE) { RGBQUAD *pal = FreeImage_GetPalette(src); for(i = 0; i < FreeImage_GetColorsUsed(src); i++) { pal[i].rgbRed = 255 - pal[i].rgbRed; pal[i].rgbGreen = 255 - pal[i].rgbGreen; pal[i].rgbBlue = 255 - pal[i].rgbBlue; } } else { for(y = 0; y < height; y++) { BYTE *bits = FreeImage_GetScanLine(src, y); for (x = 0; x < FreeImage_GetLine(src); x++) { bits[x] = ~bits[x]; } } } break; } case 24 : case 32 : { // Calculate the number of bytes per pixel (3 for 24-bit or 4 for 32-bit) const unsigned bytespp = FreeImage_GetLine(src) / width; for(y = 0; y < height; y++) { BYTE *bits = FreeImage_GetScanLine(src, y); for(x = 0; x < width; x++) { for(k = 0; k < bytespp; k++) { bits[k] = ~bits[k]; } bits += bytespp; } } break; } default: return FALSE; } } else if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) { // Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 64-bit) const unsigned wordspp = (FreeImage_GetLine(src) / width) / sizeof(WORD); for(y = 0; y < height; y++) { WORD *bits = (WORD*)FreeImage_GetScanLine(src, y); for(x = 0; x < width; x++) { for(k = 0; k < wordspp; k++) { bits[k] = ~bits[k]; } bits += wordspp; } } } else { // anything else ... return FALSE; } return TRUE; }
FREE_IMAGE_COLOR_TYPE DLL_CALLCONV FreeImage_GetColorType(FIBITMAP *dib) { RGBQUAD *rgb; const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); // special bitmap type if(image_type != FIT_BITMAP) { switch(image_type) { case FIT_UINT16: { // 16-bit greyscale TIF can be either FIC_MINISBLACK (the most common case) or FIC_MINISWHITE // you can check this using EXIF_MAIN metadata FITAG *photometricTag = NULL; if(FreeImage_GetMetadata(FIMD_EXIF_MAIN, dib, "PhotometricInterpretation", &photometricTag)) { const short *value = (short*)FreeImage_GetTagValue(photometricTag); // PHOTOMETRIC_MINISWHITE = 0 => min value is white // PHOTOMETRIC_MINISBLACK = 1 => min value is black return (*value == 0) ? FIC_MINISWHITE : FIC_MINISBLACK; } return FIC_MINISBLACK; } break; case FIT_RGB16: case FIT_RGBF: return FIC_RGB; case FIT_RGBA16: case FIT_RGBAF: return FIC_RGBALPHA; } return FIC_MINISBLACK; } // standard image type switch (FreeImage_GetBPP(dib)) { case 1: { rgb = FreeImage_GetPalette(dib); if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) { rgb++; if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) { return FIC_MINISBLACK; } } if ((rgb->rgbRed == 255) && (rgb->rgbGreen == 255) && (rgb->rgbBlue == 255)) { rgb++; if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) && (rgb->rgbBlue == 0)) { return FIC_MINISWHITE; } } return FIC_PALETTE; } case 4: case 8: // Check if the DIB has a color or a greyscale palette { int ncolors = FreeImage_GetColorsUsed(dib); int minisblack = 1; rgb = FreeImage_GetPalette(dib); for (int i = 0; i < ncolors; i++) { if ((rgb->rgbRed != rgb->rgbGreen) || (rgb->rgbRed != rgb->rgbBlue)) { return FIC_PALETTE; } // The DIB has a color palette if the greyscale isn't a linear ramp // Take care of reversed grey images if (rgb->rgbRed != i) { if ((ncolors-i-1) != rgb->rgbRed) { return FIC_PALETTE; } else { minisblack = 0; } } rgb++; } return minisblack ? FIC_MINISBLACK : FIC_MINISWHITE; } case 16: case 24: return FIC_RGB; case 32: { if (FreeImage_GetICCProfile(dib)->flags & FIICC_COLOR_IS_CMYK) { return FIC_CMYK; } if( FreeImage_HasPixels(dib) ) { // check for fully opaque alpha layer for (unsigned y = 0; y < FreeImage_GetHeight(dib); y++) { rgb = (RGBQUAD *)FreeImage_GetScanLine(dib, y); for (unsigned x = 0; x < FreeImage_GetWidth(dib); x++) { if (rgb[x].rgbReserved != 0xFF) { return FIC_RGBALPHA; } } } return FIC_RGB; } return FIC_RGBALPHA; } default : return FIC_MINISBLACK; } }
WORD fipImage::getColorsUsed() const { return FreeImage_GetColorsUsed(_dib); }
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 = NULL; png_uint_32 width, height; int color_type; int bit_depth; int pixel_depth = 0; // pixel_depth = bit_depth * channels FIBITMAP *dib = NULL; png_bytepp row_pointers = NULL; 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); // configure the decoder FREE_IMAGE_TYPE image_type = FIT_BITMAP; if(!ConfigureDecoder(png_ptr, info_ptr, flags, &image_type)) { throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; } // update image info color_type = png_get_color_type(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); pixel_depth = bit_depth * png_get_channels(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: case PNG_COLOR_TYPE_RGB_ALPHA: dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); break; case PNG_COLOR_TYPE_PALETTE: dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); if(dib) { png_colorp png_palette = NULL; int palette_entries = 0; png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries); palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib)); // store the palette RGBQUAD *palette = FreeImage_GetPalette(dib); for(int 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, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); if(dib && (pixel_depth <= 8)) { RGBQUAD *palette = FreeImage_GetPalette(dib); const int palette_entries = 1 << pixel_depth; for(int 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; } if(!dib) { throw FI_MSG_ERROR_DIB_MEMORY; } // 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 < 256) { BYTE table[256]; memset(table, 0xFF, 256); table[trans_color->gray] = 0; FreeImage_SetTransparencyTable(dib, table, 256); } // check for a full transparency table, too else if ((trans_alpha) && (pixel_depth <= 8)) { FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans); } } else if((color_type == PNG_COLOR_TYPE_PALETTE) && trans_alpha) { // transparency table FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans); } } // store the background color (only supported for FIT_BITMAP types) if ((image_type == FIT_BITMAP) && 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; }
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; }
/** * @return the number of entries in the color palette */ unsigned long fipImage::getPaletteSize() const{ return FreeImage_GetColorsUsed( pImageData ); }