/** @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; }
void write_image(const string& file, const SampleBuffer& buffer) { const float samples = static_cast<float>(buffer.samples()); FIBITMAP* dib = FreeImage_Allocate(buffer.width(), buffer.height(), 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); const unsigned int BYTESPP = FreeImage_GetLine(dib) / FreeImage_GetWidth(dib); for (unsigned int y = 0; y < FreeImage_GetHeight(dib); ++y) { BYTE* bits = FreeImage_GetScanLine(dib, y); for (unsigned int x = 0; x < FreeImage_GetWidth(dib); ++x) { vec3 c = gamma_correct(buffer.get(x, y) / samples) * 255.0f; bits[FI_RGBA_RED] = static_cast<BYTE>(c.r); bits[FI_RGBA_GREEN] = static_cast<BYTE>(c.g); bits[FI_RGBA_BLUE] = static_cast<BYTE>(c.b); bits[FI_RGBA_ALPHA] = 255; bits += BYTESPP; } } if (!FreeImage_Save(FIF_PNG, dib, file.c_str(), 0)) { string err = "Failed to save screenshot to file '"; err += file; err += '\''; throw err; } FreeImage_Unload(dib); }
void ImageLoader:: compatible() { // BITMAP数据是从下往上的, 需要翻转 FreeImage_FlipVertical(mDIB); // FreeImage是BGR顺序, 与NVTT要求的一致, 而PVRT需要RGB顺序, 两者都需要32bits数据 if (config.imageCompressionType != CT_DXTC) { // 将BGR改为RGB, 交换R channel和B channel const unsigned bytesperpixel = FreeImage_GetBPP(mDIB) / 8; const unsigned height = FreeImage_GetHeight(mDIB); const unsigned pitch = FreeImage_GetPitch(mDIB); const unsigned lineSize = FreeImage_GetLine(mDIB); BYTE* line = FreeImage_GetBits(mDIB); for (unsigned y = 0; y < height; ++y, line += pitch) { for (BYTE* pixel = line; pixel < line + lineSize; pixel += bytesperpixel) { INPLACESWAP(pixel[0], pixel[2]); } } } if (FreeImage_GetBPP(mDIB) != 32) { FIBITMAP* convertDIB = FreeImage_ConvertTo32Bits(mDIB); FreeImage_Unload(mDIB); mDIB = convertDIB; } }
unsigned DLL_CALLCONV FreeImage_GetPitch(FIBITMAP *dib) { if(dib) { FREEIMAGEHEADER *fih = (FREEIMAGEHEADER *)dib->data; return fih->external_bits ? fih->external_pitch : (FreeImage_GetLine(dib) + 3 & ~3); } return 0; }
// Takes an image from the frame buffer and compresses it int writeFrame(FIMEMORY *fiBuffer, FIBITMAP *fiImage, unsigned char imageType) { /* char msg[1024]; sprintf_s(msg, 1024, "imageType: %i", imageType); MessageBox(NULL,msg,"ADES DEBUG", MB_OK); */ imageType = 2; int errStatus = 1; u_short imageWidth, imageHeight; unsigned width, height, pitch, line; BYTE *bits; // Package image using correct compression switch(imageType) { case 0: // Send a raw frame // Get image characteristics width = FreeImage_GetWidth(fiImage); height = FreeImage_GetHeight(fiImage); pitch = FreeImage_GetPitch(fiImage); line = FreeImage_GetLine(fiImage); // Write out width and height errStatus = FreeImage_SeekMemory(fiBuffer, 0, SEEK_SET); if (errStatus != 1) break; imageWidth = htons(width); errStatus = FreeImage_WriteMemory( &imageWidth, 2, 1, fiBuffer ); if (errStatus != 1) break; imageHeight = htons(height); errStatus = FreeImage_WriteMemory( &imageHeight, 2, 1, fiBuffer ); if (errStatus != 1) break; // Write out image (convert the bitmap to raw bits, top-left pixel first) bits = (BYTE*)malloc(height * pitch); FreeImage_ConvertToRawBits(bits, fiImage, pitch, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK, TRUE); errStatus = FreeImage_WriteMemory( bits, height*pitch*sizeof(BYTE), 1, fiBuffer ); free(bits); if (errStatus != 1) break; break; default: // Send a jpg frame errStatus = FreeImage_SeekMemory(fiBuffer, 0, SEEK_SET); if (errStatus != 1) break; errStatus = FreeImage_SaveToMemory(FIF_JPEG, fiImage, fiBuffer, convertToJpegFlag(imageType)); if (errStatus != 1) break; break; } // Clean up and exit return errStatus; }
int main (int argc, char ** argv) { if (argc != 2){ printf("you need to give me the number of frames to captures\n"); exit(-1); } int num_frames = atoi(argv[1]); initialize_pru(); start_pru(); FILE * image_data = fopen("/media/usb/image.data", "w"); if (image_data == NULL){ fprintf(stderr, "Failed to open image output file"); exit(-1); } const char *version = FreeImage_GetVersion(); printf("Freeimage version %s\n", version); FIBITMAP* dib = FreeImage_Allocate(320, 203, 16, 0xF800, 0x07E0,0x001F); // allocate 320x203 RGB565 bitmap int bytespp = FreeImage_GetLine(dib)/FreeImage_GetWidth(dib); FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); if (image_type == FIT_BITMAP){ printf("1\n"); } printf("%d %d\n", FreeImage_GetHeight(dib), FreeImage_GetWidth(dib)); BYTE * bits = FreeImage_GetBits(dib); FILE * fp = fopen("image.data", "rb"); char filename[] = "/root/1314-BeagleBone-Quadcopter/code/ControlTower/ramfs/latest_image.bmp"; int i = 0; for (i = 0; i < num_frames; i++){ while(i==pruDataMem_int[100]){usleep(100000);} int buffer = pruDataMem_int[1]; printf("%d buffer=%d\n", pruDataMem_int[100], buffer); if (i%10==0){ memcpy(bits, pru1_ddr+buffer*320*240*2, 320*203*2); FreeImage_Save(FIF_BMP, dib, filename,0); } } uninitialize_pru(); fflush(image_data); printf("%d\n", ((volatile uint8_t *)pru1_ddr)[0]); fclose(image_data); prussdrv_pru_disable (PRU_NUM); prussdrv_exit (); return(0); }
static BOOL DLL_CALLCONV Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) { if(!dib || !handle) return FALSE; FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); if((image_type != FIT_RGBF) && (image_type != FIT_FLOAT)) { return FALSE; } unsigned width = FreeImage_GetWidth(dib); unsigned height = FreeImage_GetHeight(dib); unsigned lineWidth = FreeImage_GetLine(dib); // save image as Little Endian const float scalefactor = -1.0F; char buffer[PFM_MAXLINE]; // temporary buffer whose size should be enough for what we need // Find the appropriate magic number for this file type char magic = 0; switch(image_type) { case FIT_RGBF: magic = 'F'; // RGBF break; case FIT_FLOAT: magic = 'f'; // float greyscale break; default: return FALSE; } // Write the header info sprintf(buffer, "P%c\n%d %d\n%f\n", magic, width, height, scalefactor); io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle); // Write the image data for (unsigned y = 0; y < height; y++) { BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y); io->write_proc(bits, 1, lineWidth, handle); } return TRUE; }
/** @brief Fills an image with the specified color. This function sets all pixels of an image to the color provided through the color parameter. Since this should work for all image types supported by FreeImage, the pointer color must point to a memory location, which is at least as large as the image's color value, if this size is greater than 4 bytes. As the color is specified by an RGBQUAD structure for all images of type FIT_BITMAP (including all palletized images), the smallest possible size of this memory is the size of the RGBQUAD structure, which uses 4 bytes. So, color must point to a double, if the image to be filled is of type FIT_DOUBLE and point to a RGBF structure if the image is of type FIT_RGBF and so on. However, the fill color is always specified through a RGBQUAD structure for all images of type FIT_BITMAP. So, for 32- and 24-bit images, the red, green and blue members of the RGBQUAD structure are directly used for the image's red, green and blue channel respectively. Although alpha transparent RGBQUAD colors are supported, the alpha channel of a 32-bit image never gets modified by this function. A fill color with an alpha value smaller than 255 gets blended with the image's actual background color, which is determined from the image's bottom-left pixel. So, currently using alpha enabled colors, assumes the image to be unicolor before the fill operation. However, the RGBQUAD's rgbReserved member is only taken into account, if option FI_COLOR_IS_RGBA_COLOR has been specified. For 16-bit images, the red-, green- and blue components of the specified color are transparently translated into either the 16-bit 555 or 565 representation. This depends on the image's actual red- green- and blue masks. Special attention must be payed for palletized images. Generally, the RGB color specified is looked up in the image's palette. The found palette index is then used to fill the image. There are some option flags, that affect this lookup process: no option specified (0x00) Uses the color, that is nearest to the specified color. This is the default behavior and should always find a color in the palette. However, the visual result may far from what was expected and mainly depends on the image's palette. FI_COLOR_FIND_EQUAL_COLOR (0x02) Searches the image's palette for the specified color but only uses the returned palette index, if the specified color exactly matches the palette entry. Of course, depending on the image's actual palette entries, this operation may fail. In this case, the function falls back to option FI_COLOR_ALPHA_IS_INDEX and uses the RGBQUAD's rgbReserved member (or its low nibble for 4-bit images or its least significant bit (LSB) for 1-bit images) as the palette index used for the fill operation. FI_COLOR_ALPHA_IS_INDEX (0x04) Does not perform any color lookup from the palette, but uses the RGBQUAD's alpha channel member rgbReserved as the palette index to be used for the fill operation. However, for 4-bit images, only the low nibble of the rgbReserved member are used and for 1-bit images, only the least significant bit (LSB) is used. This function fails if any of dib and color is NULL. @param dib The image to be filled. @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. @return Returns TRUE on success, FALSE otherwise. This function fails if any of dib and color is NULL. */ BOOL DLL_CALLCONV FreeImage_FillBackground(FIBITMAP *dib, const void *color, int options) { if (!FreeImage_HasPixels(dib)) { return FALSE; } if (!color) { return FALSE; } // handle FIT_BITMAP images with FreeImage_FillBackground() if (FreeImage_GetImageType(dib) == FIT_BITMAP) { return FillBackgroundBitmap(dib, (RGBQUAD *)color, options); } // first, construct the first scanline (bottom line) unsigned bytespp = (FreeImage_GetBPP(dib) / 8); BYTE *src_bits = FreeImage_GetScanLine(dib, 0); BYTE *dst_bits = src_bits; for (unsigned x = 0; x < FreeImage_GetWidth(dib); x++) { memcpy(dst_bits, color, bytespp); dst_bits += bytespp; } // then, copy the first scanline into all following scanlines unsigned height = FreeImage_GetHeight(dib); unsigned pitch = FreeImage_GetPitch(dib); unsigned bytes = FreeImage_GetLine(dib); dst_bits = src_bits + pitch; for (unsigned y = 1; y < height; y++) { memcpy(dst_bits, src_bits, bytes); dst_bits += pitch; } return TRUE; }
FIBITMAP* DLL_CALLCONV FIA_ColourConvertBGRtoRGB (FIBITMAP * src) { FIBITMAP *dst = NULL; int x, y, bytespp; if (!src) return NULL; if (FIA_IsGreyScale(src)==1) return NULL; dst = FreeImage_Clone(src); // Calculate the number of bytes per pixel (3 for 24-bit or 4 for 32-bit) bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src); for(y = 0; y < FreeImage_GetHeight(src); y++) { BYTE *src_bits = FreeImage_GetScanLine(src, y); BYTE *dst_bits = FreeImage_GetScanLine(dst, y); for(x = 0; x < FreeImage_GetWidth(src); x++) { // reverse colour bytes dst_bits[FI_RGBA_RED] = src_bits[FI_RGBA_BLUE]; dst_bits[FI_RGBA_GREEN] = src_bits[FI_RGBA_GREEN]; dst_bits[FI_RGBA_BLUE] = src_bits[FI_RGBA_RED]; dst_bits[FI_RGBA_ALPHA] = 0; // jump to next pixel src_bits += bytespp; dst_bits += bytespp; } } return dst; }
/** @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; }
FIBITMAP * DLL_CALLCONV FreeImage_Clone(FIBITMAP *dib) { if(!dib) { return NULL; } FREE_IMAGE_TYPE type = FreeImage_GetImageType(dib); unsigned width = FreeImage_GetWidth(dib); unsigned height = FreeImage_GetHeight(dib); unsigned bpp = FreeImage_GetBPP(dib); const BYTE *ext_bits = ((FREEIMAGEHEADER *)dib->data)->external_bits; // check for pixel availability ... BOOL header_only = FreeImage_HasPixels(dib) ? FALSE : TRUE; // check whether this image has masks defined ... BOOL need_masks = (bpp == 16 && type == FIT_BITMAP) ? TRUE : FALSE; // allocate a new dib FIBITMAP *new_dib = FreeImage_AllocateHeaderT(header_only, type, width, height, bpp, FreeImage_GetRedMask(dib), FreeImage_GetGreenMask(dib), FreeImage_GetBlueMask(dib)); if (new_dib) { // save ICC profile links FIICCPROFILE *src_iccProfile = FreeImage_GetICCProfile(dib); FIICCPROFILE *dst_iccProfile = FreeImage_GetICCProfile(new_dib); // save metadata links METADATAMAP *src_metadata = ((FREEIMAGEHEADER *)dib->data)->metadata; METADATAMAP *dst_metadata = ((FREEIMAGEHEADER *)new_dib->data)->metadata; // calculate the size of the src image // align the palette and the pixels on a FIBITMAP_ALIGNMENT bytes alignment boundary // palette is aligned on a 16 bytes boundary // pixels are aligned on a 16 bytes boundary // when using a user provided pixel buffer, force a 'header only' calculation size_t dib_size = FreeImage_GetInternalImageSize(header_only || ext_bits, width, height, bpp, need_masks); // copy the bitmap + internal pointers (remember to restore new_dib internal pointers later) memcpy(new_dib->data, dib->data, dib_size); // reset ICC profile link for new_dib memset(dst_iccProfile, 0, sizeof(FIICCPROFILE)); // restore metadata link for new_dib ((FREEIMAGEHEADER *)new_dib->data)->metadata = dst_metadata; // reset thumbnail link for new_dib ((FREEIMAGEHEADER *)new_dib->data)->thumbnail = NULL; // copy possible ICC profile FreeImage_CreateICCProfile(new_dib, src_iccProfile->data, src_iccProfile->size); dst_iccProfile->flags = src_iccProfile->flags; // copy metadata models for(METADATAMAP::iterator i = (*src_metadata).begin(); i != (*src_metadata).end(); i++) { int model = (*i).first; TAGMAP *src_tagmap = (*i).second; if(src_tagmap) { // create a metadata model TAGMAP *dst_tagmap = new(std::nothrow) TAGMAP(); if(dst_tagmap) { // fill the model for(TAGMAP::iterator j = src_tagmap->begin(); j != src_tagmap->end(); j++) { std::string dst_key = (*j).first; FITAG *dst_tag = FreeImage_CloneTag( (*j).second ); // assign key and tag value (*dst_tagmap)[dst_key] = dst_tag; } // assign model and tagmap (*dst_metadata)[model] = dst_tagmap; } } } // copy the thumbnail FreeImage_SetThumbnail(new_dib, FreeImage_GetThumbnail(dib)); // copy user provided pixel buffer (if any) if(ext_bits) { const unsigned pitch = FreeImage_GetPitch(dib); const unsigned linesize = FreeImage_GetLine(dib); for(unsigned y = 0; y < height; y++) { memcpy(FreeImage_GetScanLine(new_dib, y), ext_bits, linesize); ext_bits += pitch; } } return new_dib; } return NULL; }
/** @brief Fills a FIT_BITMAP image with the specified color. This function does the dirty work for FreeImage_FillBackground for FIT_BITMAP images. @param dib The image to be filled. @param color The color, the specified image should be filled with. @param options Options that affect the color search process for palletized images. @return Returns TRUE on success, FALSE otherwise. This function fails if any of the dib and color is NULL or the provided image is not a FIT_BITMAP image. */ static BOOL FillBackgroundBitmap(FIBITMAP *dib, const RGBQUAD *color, int options) { if ((!dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP)) { return FALSE;; } if (!color) { return FALSE; } const RGBQUAD *color_intl = color; unsigned bpp = FreeImage_GetBPP(dib); unsigned width = FreeImage_GetWidth(dib); unsigned height = FreeImage_GetHeight(dib); FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib); // get a pointer to the first scanline (bottom line) BYTE *src_bits = FreeImage_GetScanLine(dib, 0); BYTE *dst_bits = src_bits; BOOL supports_alpha = ((bpp >= 24) || ((bpp == 8) && (color_type != FIC_PALETTE))); // Check for RGBA case if bitmap supports alpha // blending (8-bit greyscale, 24- or 32-bit images) if (supports_alpha && (options & FI_COLOR_IS_RGBA_COLOR)) { if (color->rgbReserved == 0) { // the fill color is fully transparent; we are done return TRUE; } // Only if the fill color is NOT fully opaque, draw it with // the (much) slower FreeImage_DrawLine function and return. // Since we do not have the FreeImage_DrawLine function in this // release, just assume to have an unicolor background and fill // all with an 'alpha-blended' color. if (color->rgbReserved < 255) { // If we will draw on an unicolor background, it's // faster to draw opaque with an alpha blended color. // So, first get the color from the first pixel in the // image (bottom-left pixel). RGBQUAD bgcolor; if (bpp == 8) { bgcolor = FreeImage_GetPalette(dib)[*src_bits]; } else { bgcolor.rgbBlue = src_bits[FI_RGBA_BLUE]; bgcolor.rgbGreen = src_bits[FI_RGBA_GREEN]; bgcolor.rgbRed = src_bits[FI_RGBA_RED]; bgcolor.rgbReserved = 0xFF; } RGBQUAD blend; GetAlphaBlendedColor(&bgcolor, color_intl, &blend); color_intl = &blend; } } int index = (bpp <= 8) ? GetPaletteIndex(dib, color_intl, options, &color_type) : 0; if (index == -1) { // No palette index found for a palletized // image. This should never happen... return FALSE; } // first, build the first scanline (line 0) switch (bpp) { case 1: { unsigned bytes = (width / 8); memset(dst_bits, ((index == 1) ? 0xFF : 0x00), bytes); //int n = width % 8; int n = width & 7; if (n) { if (index == 1) { // set n leftmost bits dst_bits[bytes] |= (0xFF << (8 - n)); } else { // clear n leftmost bits dst_bits[bytes] &= (0xFF >> n); } } break; } case 4: { unsigned bytes = (width / 2); memset(dst_bits, (index | (index << 4)), bytes); //if (bytes % 2) { if (bytes & 1) { dst_bits[bytes] &= 0x0F; dst_bits[bytes] |= (index << 4); } break; } case 8: { memset(dst_bits, index, FreeImage_GetLine(dib)); break; } case 16: { WORD wcolor = RGBQUAD_TO_WORD(dib, color_intl); for (unsigned x = 0; x < width; x++) { ((WORD *)dst_bits)[x] = wcolor; } break; } case 24: { RGBTRIPLE rgbt = *((RGBTRIPLE *)color_intl); for (unsigned x = 0; x < width; x++) { ((RGBTRIPLE *)dst_bits)[x] = rgbt; } break; } case 32: { RGBQUAD rgbq; rgbq.rgbBlue = ((RGBTRIPLE *)color_intl)->rgbtBlue; rgbq.rgbGreen = ((RGBTRIPLE *)color_intl)->rgbtGreen; rgbq.rgbRed = ((RGBTRIPLE *)color_intl)->rgbtRed; rgbq.rgbReserved = 0xFF; for (unsigned x = 0; x < width; x++) { ((RGBQUAD *)dst_bits)[x] = rgbq; } break; } default: return FALSE; } // Then, copy the first scanline into all following scanlines. // 'src_bits' is a pointer to the first scanline and is already // set up correctly. if (src_bits) { unsigned pitch = FreeImage_GetPitch(dib); unsigned bytes = FreeImage_GetLine(dib); dst_bits = src_bits + pitch; for (unsigned y = 1; y < height; y++) { memcpy(dst_bits, src_bits, bytes); dst_bits += pitch; } } return TRUE; }
/// Performs vertical image filtering void CResizeEngine::verticalFilter(FIBITMAP *src, unsigned src_width, unsigned src_height, FIBITMAP *dst, unsigned dst_width, unsigned dst_height) { if(src_height == dst_height) { // no scaling required, just copy BYTE *src_bits = FreeImage_GetBits(src); BYTE *dst_bits = FreeImage_GetBits(dst); memcpy(dst_bits, src_bits, dst_height * FreeImage_GetPitch(dst)); } else { unsigned index; // pixel index // allocate and calculate the contributions CWeightsTable weightsTable(m_pFilter, dst_height, src_height); // step through columns switch(FreeImage_GetBPP(src)) { case 8: case 24: case 32: { // Calculate the number of bytes per pixel (1 for 8-bit, 3 for 24-bit or 4 for 32-bit) unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src); unsigned src_pitch = FreeImage_GetPitch(src); unsigned dst_pitch = FreeImage_GetPitch(dst); for(unsigned x = 0; x < dst_width; x++) { index = x * bytespp; // work on column x in dst BYTE *dst_bits = FreeImage_GetBits(dst) + index; // scale each column for(unsigned y = 0; y < dst_height; y++) { // loop through column double value[4] = {0, 0, 0, 0}; // 4 = 32bpp max int iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary int iRight = weightsTable.getRightBoundary(y); // retrieve right boundary BYTE *src_bits = FreeImage_GetScanLine(src, iLeft) + index; for(int i = iLeft; i <= iRight; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel double weight = weightsTable.getWeight(y, i-iLeft); for (unsigned j = 0; j < bytespp; j++) { value[j] += (weight * (double)src_bits[j]); } src_bits += src_pitch; } // clamp and place result in destination pixel for (unsigned j = 0; j < bytespp; j++) { dst_bits[j] = (BYTE)MIN(MAX((int)0, (int)(value[j] + 0.5)), (int)255); } dst_bits += dst_pitch; } } } break; case 16: case 48: case 64: { // Calculate the number of words per pixel (1 for 16-bit, 3 for 48-bit or 4 for 96-bit) unsigned wordspp = (FreeImage_GetLine(src) / FreeImage_GetWidth(src)) / sizeof(WORD); unsigned src_pitch = FreeImage_GetPitch(src) / sizeof(WORD); unsigned dst_pitch = FreeImage_GetPitch(dst) / sizeof(WORD); for(unsigned x = 0; x < dst_width; x++) { index = x * wordspp; // work on column x in dst WORD *dst_bits = (WORD*)FreeImage_GetBits(dst) + index; // scale each column for(unsigned y = 0; y < dst_height; y++) { // loop through column double value[4] = {0, 0, 0, 0}; // 4 = 64bpp max int iLeft = weightsTable.getLeftBoundary(y); // retrieve left boundary int iRight = weightsTable.getRightBoundary(y); // retrieve right boundary WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, iLeft) + index; for(int i = iLeft; i <= iRight; i++) { // scan between boundaries // accumulate weighted effect of each neighboring pixel double weight = weightsTable.getWeight(y, i-iLeft); for (unsigned j = 0; j < wordspp; j++) { value[j] += (weight * (double)src_bits[j]); } src_bits += src_pitch; } // clamp and place result in destination pixel for (unsigned j = 0; j < wordspp; j++) { dst_bits[j] = (BYTE)MIN(MAX((WORD)0, (WORD)(value[j] + 0.5)), (WORD)0xFFFF); } dst_bits += dst_pitch; } } } break; } } }
template < typename Tsrc > int LOGIC < Tsrc >::MaskImage (FIBITMAP * src, FIBITMAP * mask) { if (mask == NULL || src == NULL) { return FIA_ERROR; } // Have to be the same size if (FIA_CheckDimensions (src, mask) == FIA_ERROR) { return FIA_ERROR; } // Mask has to be 8 bit if (FreeImage_GetBPP (mask) != 8 || FreeImage_GetImageType (mask) != FIT_BITMAP) { return FIA_ERROR; } int width = FreeImage_GetWidth (src); int height = FreeImage_GetHeight (src); bool greyscale_image = true; if(FreeImage_GetImageType(src) == FIT_BITMAP && FreeImage_GetBPP(src) > 8) { greyscale_image = false; } if(greyscale_image) { for(register int y = 0; y < height; y++) { Tsrc *src_ptr = (Tsrc *) FreeImage_GetScanLine (src, y); unsigned char *mask_ptr = (unsigned char *) FreeImage_GetScanLine (mask, y); for(register int x = 0; x < width; x++) { if (!mask_ptr[x]) src_ptr[x] = 0; } } } else { int bytespp = FreeImage_GetLine (src) / FreeImage_GetWidth (src); for(register int y = 0; y < height; y++) { BYTE *src_ptr = (BYTE *) FreeImage_GetScanLine (src, y); BYTE *mask_ptr = (BYTE *) FreeImage_GetScanLine (mask, y); for(register int x = 0; x < width; x++) { if (!mask_ptr[x]) { src_ptr[FI_RGBA_RED] = 0; src_ptr[FI_RGBA_GREEN] = 0; src_ptr[FI_RGBA_BLUE] = 0; if (bytespp == 4) src_ptr[FI_RGBA_ALPHA] = 0; } src_ptr += bytespp; } } } return FIA_SUCCESS; }
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; } }
bool sr::Texture::LoadFromFile(const std::string& relativePath, const sr::FileSystem& fileSystem) { Unload(); Name(relativePath); const std::string fullPath = fileSystem.GetFullPath(relativePath); const char* filename = fullPath.c_str(); const GLenum image_format = GL_RGB; // format the image is in const GLint internal_format = GL_RGB; // format to store the image in const GLint level = 0; // mipmapping level const GLint border = 0; // border size //check the file signature and deduce its format FREE_IMAGE_FORMAT fif = FreeImage_GetFileType(filename, 0); // Try to guess the file format from the file extension: if(fif == FIF_UNKNOWN) fif = FreeImage_GetFIFFromFilename(filename); // if still unkown, return failure if(fif == FIF_UNKNOWN || !FreeImage_FIFSupportsReading(fif)) return false; //check that the plugin has reading capabilities and load the file FIBITMAP* const dib = FreeImage_Load(fif, filename, PNG_DEFAULT); if(!dib) return false; BYTE* const bits = FreeImage_GetBits(dib); const unsigned int width = FreeImage_GetWidth(dib); const unsigned int height = FreeImage_GetHeight(dib); // if this somehow one of these failed (they shouldn't), return failure if((bits == nullptr) || (width == 0) || (height == 0)) return false; // Calculate the number of bytes per pixel (3 for 24-bit or 4 for 32-bit) const int bpp = FreeImage_GetLine(dib) / FreeImage_GetWidth(dib); // Exchange red and blue channel because FreeImage loads in BGRA format; while we need it as RGBA: for(unsigned y = 0; y < height; ++y) { BYTE* line = FreeImage_GetScanLine(dib, y); for( unsigned x = 0; x < width; ++x ) { const BYTE r = line[FI_RGBA_BLUE]; const BYTE b = line[FI_RGBA_RED]; line[FI_RGBA_RED] = r; line[FI_RGBA_BLUE] = b; // jump to next pixel line += bpp; } } // Generate glGenTextures(1, &id); glBindTexture(GL_TEXTURE_2D, id); glTexImage2D(GL_TEXTURE_2D, level, internal_format, width, height, border, image_format, GL_UNSIGNED_BYTE, bits); // Configure glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); GLfloat maxAniso(0.0f); glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAniso); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAniso); // Free FreeImage's copy of the data FreeImage_Unload(dib); if(id != 0) { size = glm::uvec2(width, height); Loaded(true); return true; } else { return false; } }
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); for (unsigned k = 0; k < ch_size / 3; 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); } } #ifndef FREEIMAGE_BIGENDIAN 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); }
/** open the given bitmap file and guarantee that the pixels can be accessed by RGB ( i.e. convert if indexed ) @return true -> opened and converted correct */ bool Vt2IsoImageFreeImage_c::openBitmap( const char* filename ) { reset(); i_curScanLineY = -1; if (isOstream()) getOstream() << std::endl << "Opening " << filename << std::endl; FREE_IMAGE_FORMAT fif = FIF_UNKNOWN; // check the file signature and deduce its format // (the second argument is currently not used by FreeImage) fif = FreeImage_GetFileType(filename, 0); if(fif == FIF_UNKNOWN) { // no signature ? // try to guess the file format from the file extension fif = FreeImage_GetFIFFromFilename(filename); if (isOstream()) getOstream() << "File type not recognized" << std::endl; } // check that the plugin has reading capabilities ... if((fif != FIF_UNKNOWN) && FreeImage_FIFSupportsReading(fif)) { // ok, let's load the file bitmap = FreeImage_Load(fif, filename, 0); } else { // hardcore - try with BMP if (isOstream()) getOstream() << "Try with BMP" << std::endl; bitmap = FreeImage_Load(FIF_BMP, filename, 0); if ( bitmap == NULL ) { // next hardcoretry with png if (isOstream()) getOstream() << "Try with PNG" << std::endl; bitmap = FreeImage_Load(FIF_PNG, filename, 0); } if ( bitmap == NULL ) { // next hardcoretry with jpg if (isOstream()) getOstream() << "Try with JPEG" << std::endl; bitmap = FreeImage_Load(FIF_JPEG, filename, 0); } } if ( bitmap == NULL ) { if (isOstream()) getOstream() << "Error loading bitmap file" << std::endl; return false; } else if (isOstream()) getOstream() << "Bitmap successfully loaded" << std::endl; if (FreeImage_GetBPP(bitmap) > 8) { // convert to 32-Bit standard bitmap ONLY if NOT palettized! FIBITMAP *tmp = FreeImage_ConvertTo32Bits(bitmap); FreeImage_Unload(bitmap); bitmap = tmp; } ui_width = FreeImage_GetWidth(bitmap); ui_height = FreeImage_GetHeight(bitmap); // Calculate the number of bytes per pixel (3 for 24-bit or 4 for 32-bit) bytespp = FreeImage_GetLine(bitmap) / FreeImage_GetWidth(bitmap); mb_palettized = false; if (FreeImage_GetBPP(bitmap) <= 8) { mi_colourMismatch = -1; // default: no colour mismatches... for (int i=0; i<(16+216); i++) { // check all colours if the bitmap uses the ISO-palette if ( (vtColourTable[i].bgrRed != FreeImage_GetPalette (bitmap)[i].rgbRed) || (vtColourTable[i].bgrGreen != FreeImage_GetPalette (bitmap)[i].rgbGreen) || (vtColourTable[i].bgrBlue != FreeImage_GetPalette (bitmap)[i].rgbBlue) ) { mi_colourMismatch = i; break; } } mb_palettized = true; if (isOstream()) getOstream() << " palettized (depth="<<FreeImage_GetBPP(bitmap)<<"). "; return true; } else { if (isOstream()) getOstream() << " as RGB (depth="<<FreeImage_GetBPP(bitmap)<<"). "; return true; } }
unsigned fipImage::getLine() const { return FreeImage_GetLine(_dib); }
// MAIN int main(int argc, char ** argv) { int scene_id = 0; bool use_octree = false; char basename[256] = ""; if (argc > 1) scene_id = atoi(argv[1]); if (argc > 2) strcpy(basename, argv[2]); // scene_id 0, 1, 2, 3 is for tp 1 tests; switch (scene_id) { case 0: fill_red(output_image); break; case 1: fill(output_image, vector_init(0.7, 0.3, 0.1)); fill_rect(output_image, vector_init(0.2, 0.6, 0.7), vector_init(WIDTH / 4, HEIGHT / 5, 0), vector_init(WIDTH / 3, HEIGHT / 4, 0)); break; case 2: horizontal_gradient(output_image, vector_init(0, 0, 1), vector_init(1, 1, 1)); break; case 3: horizontal_gradient(output_image, vector_init(0, 0, 1), vector_init(1, 1, 1)); fill_circle(output_image, WIDTH / 20, vector_init(4 * WIDTH / 5, 4 * HEIGHT / 5, 0), vector_init(1, 1, 0)); fill_rect(output_image, vector_init(0.1, 0.8, 0.4), vector_init(0, 0, 0), vector_init(WIDTH, HEIGHT / 4, 0)); break; case 4: horizontal_gradient(output_image, vector_init(0.5, 0.8, 1), vector_init(1, 1, 1)); fill_circle(output_image, WIDTH / 20, vector_init(4 * WIDTH / 5, 4 * HEIGHT / 5, 0), vector_init(1, 1, 0)); fill_circle(output_image, WIDTH / 21, vector_init(3 * WIDTH / 5, 3 * HEIGHT / 5, 0), vector_init(1, 0.3, 0.1)); fill_rect(output_image, vector_init(0.85, 0.85, 0.3), vector_init(0, 0, 0), vector_init(WIDTH, HEIGHT / 4, 0)); break; default: setup_scene(scene_id - 5); raytrace(); break; } #ifdef USE_FREEIMAGE FreeImage_Initialise(); FIBITMAP *bitmap = FreeImage_Allocate(WIDTH, HEIGHT, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); if (bitmap) { // bitmap successfully created! // Calculate the number of bytes per pixel (3 for 24-bit or 4 for 32-bit) color *ptr = output_image; int bytespp = FreeImage_GetLine(bitmap) / FreeImage_GetWidth(bitmap); for(unsigned y = 0; y < FreeImage_GetHeight(bitmap); y++) { BYTE *bits = FreeImage_GetScanLine(bitmap, y); for(unsigned x = 0; x < FreeImage_GetWidth(bitmap); x++) { // Set pixel color to green with a transparency of 128 *ptr = vector_clamp(*ptr, 0.f, 1.f); bits[FI_RGBA_RED] = ptr->x*255; bits[FI_RGBA_GREEN] = ptr->y*255; bits[FI_RGBA_BLUE] = ptr->z*255; bits[FI_RGBA_ALPHA] = 255; // jump to next pixel bits += bytespp; ptr++; } } // FreeImage_Save(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, const char *filename, int flags FI_DEFAULT(0)); char filename[256]; strcpy(filename, basename); strcat(filename, ".png"); if (FreeImage_Save(FIF_PNG, bitmap, filename, 0)) { // bitmap successfully saved! } FreeImage_Unload(bitmap); } FreeImage_DeInitialise(); #endif // le code ci dessous crée et sauvegarde une image sous le nom output.png dans le repertoire d'execution { FILE *fp = NULL; char filename[256]; strcpy(filename, basename); strcat(filename, ".ppm"); fp = fopen(filename, "w"); if (fp) { // création réussi fprintf(fp, "P3\n"); fprintf(fp, "%d %d\n255\n", WIDTH, HEIGHT); // La c'est pour faire la boucle for (unsigned y = 0; y < HEIGHT; y++) { color *ptr = &(output_image[(HEIGHT - y - 1) * WIDTH]); for (unsigned x = 0; x < WIDTH; x++) { *ptr = vector_clamp(*ptr, 0.f, 1.f); unsigned char r = ptr->x * 255; unsigned char g = ptr->y * 255; unsigned char b = ptr->z * 255; ptr++; fprintf(fp, "%d %d %d ", r, g, b); } fprintf(fp, "\n"); } fclose(fp); } } return 0; }
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 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; }
unsigned DLL_CALLCONV FreeImage_GetPitch(FIBITMAP *dib) { return dib ? FreeImage_GetLine(dib) + 3 & ~3 : 0; }
/** @brief Applies palette index mapping for one or several indices on a 1-, 4- or 8-bit palletized image. This function maps up to <i>count</i> palette indices specified in <i>srcindices</i> to these specified in <i>dstindices</i>. Thereby, index <i>srcindices[N]</i>, if present in the image, will be replaced by index <i>dstindices[N]</i>. If parameter <i>swap</i> is TRUE, additionally all indices specified in <i>dstindices</i> are also mapped to these specified in <i>srcindices</i>.<br> The function returns the number of pixels changed or zero, if no pixels were changed. Both arrays <i>srcindices</i> and <i>dstindices</i> are assumed not to hold less than <i>count</i> indices.<br> <b>Note, that this behaviour is different from what FreeImage_ApplyColorMapping() does, which modifies the actual image data on palletized images.</b> @param dib Input/output image to be processed. @param srcindices Array of palette indices to be used as the mapping source. @param dstindices Array of palette indices to be used as the mapping destination. @param count The number of palette indices to be mapped. This is the size of both <i>srcindices</i> and <i>dstindices</i>. @param swap If TRUE, source and destination palette indices are swapped, that is, each destination index is also mapped to the corresponding source index. @return Returns the total number of pixels changed. */ unsigned DLL_CALLCONV FreeImage_ApplyPaletteIndexMapping(FIBITMAP *dib, BYTE *srcindices, BYTE *dstindices, unsigned count, BOOL swap) { unsigned result = 0; if ((!dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP)) { return 0; } // validate parameters if ((!srcindices) || (!dstindices)|| (count < 1)) { return 0; } unsigned height = FreeImage_GetHeight(dib); unsigned width = FreeImage_GetLine(dib); BYTE *a, *b; int bpp = FreeImage_GetBPP(dib); switch (bpp) { case 1: { return result; } case 4: { int skip_last = (FreeImage_GetWidth(dib) & 0x01); unsigned max_x = width - 1; for (unsigned y = 0; y < height; y++) { BYTE *bits = FreeImage_GetScanLine(dib, y); for (unsigned x = 0; x < width; x++) { int start = ((skip_last) && (x == max_x)) ? 1 : 0; for (int cn = start; cn < 2; cn++) { for (unsigned j = 0; j < count; j++) { a = srcindices; b = dstindices; for (int i = ((swap) ? 0 : 1); i < 2; i++) { if (GET_NIBBLE(cn, bits[x]) == (a[j] & 0x0F)) { SET_NIBBLE(cn, bits[x], b[j]); result++; j = count; break; } a = dstindices; b = srcindices; } } } } } return result; } case 8: { for (unsigned y = 0; y < height; y++) { BYTE *bits = FreeImage_GetScanLine(dib, y); for (unsigned x = 0; x < width; x++) { for (unsigned j = 0; j < count; j++) { a = srcindices; b = dstindices; for (int i = ((swap) ? 0 : 1); i < 2; i++) { if (bits[x] == a[j]) { bits[x] = b[j]; result++; j = count; break; } a = dstindices; b = srcindices; } } } } return result; } default: { return 0; } } }
WORD fipImage::getLine() const { return FreeImage_GetLine(_dib); }
FIBITMAP * DLL_CALLCONV FreeImage_ConvertToRGB16(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: { // convert to 24-bit if needed if((FreeImage_GetBPP(dib) == 24) || (FreeImage_GetBPP(dib) == 32)) { src = dib; } else { src = FreeImage_ConvertTo24Bits(dib); if(!src) return NULL; } break; } case FIT_UINT16: // allow conversion from unsigned 16-bit src = dib; break; case FIT_RGB16: // RGB16 type : clone the src return FreeImage_Clone(dib); break; case FIT_RGBA16: // allow conversion from 64-bit RGBA (ignore the alpha channel) src = dib; break; default: return NULL; } // allocate dst image const unsigned width = FreeImage_GetWidth(src); const unsigned height = FreeImage_GetHeight(src); dst = FreeImage_AllocateT(FIT_RGB16, 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 RGB16 switch(src_type) { case FIT_BITMAP: { // Calculate the number of bytes per pixel (1 for 8-bit, 3 for 24-bit or 4 for 32-bit) const unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src); for(unsigned y = 0; y < height; y++) { const BYTE *src_bits = (BYTE*)FreeImage_GetScanLine(src, y); FIRGB16 *dst_bits = (FIRGB16*)FreeImage_GetScanLine(dst, y); for(unsigned x = 0; x < width; x++) { dst_bits[x].red = src_bits[FI_RGBA_RED] << 8; dst_bits[x].green = src_bits[FI_RGBA_GREEN] << 8; dst_bits[x].blue = src_bits[FI_RGBA_BLUE] << 8; src_bits += bytespp; } } } break; case FIT_UINT16: { for(unsigned y = 0; y < height; y++) { const WORD *src_bits = (WORD*)FreeImage_GetScanLine(src, y); FIRGB16 *dst_bits = (FIRGB16*)FreeImage_GetScanLine(dst, y); for(unsigned x = 0; x < width; x++) { // convert by copying greyscale channel to each R, G, B channels dst_bits[x].red = src_bits[x]; dst_bits[x].green = src_bits[x]; dst_bits[x].blue = src_bits[x]; } } } break; case FIT_RGBA16: { for(unsigned y = 0; y < height; y++) { const FIRGBA16 *src_bits = (FIRGBA16*)FreeImage_GetScanLine(src, y); FIRGB16 *dst_bits = (FIRGB16*)FreeImage_GetScanLine(dst, y); for(unsigned x = 0; x < width; x++) { // convert and skip alpha channel dst_bits[x].red = src_bits[x].red; dst_bits[x].green = src_bits[x].green; dst_bits[x].blue = src_bits[x].blue; } } } break; default: break; } if(src != dib) { FreeImage_Unload(src); } return dst; }
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; }
/** Copy or convert & copy decoded pixels into the dib @param pDecoder Decoder handle @param out_guid_format Target guid format @param dib Output dib @param width Image width @param height Image height @return Returns 0 if successful, returns ERR otherwise */ static ERR CopyPixels(PKImageDecode *pDecoder, PKPixelFormatGUID out_guid_format, FIBITMAP *dib, int width, int height) { PKFormatConverter *pConverter = NULL; // pixel format converter ERR error_code = 0; // error code as returned by the interface BYTE *pb = NULL; // local buffer used for pixel format conversion // image dimensions const PKRect rect = {0, 0, width, height}; try { // get input file pixel format ... PKPixelFormatGUID in_guid_format; error_code = pDecoder->GetPixelFormat(pDecoder, &in_guid_format); JXR_CHECK(error_code); // is a format conversion needed ? if(IsEqualGUID(out_guid_format, in_guid_format)) { // no conversion, load bytes "as is" ... // get a pointer to dst pixel data BYTE *dib_bits = FreeImage_GetBits(dib); // get dst pitch (count of BYTE for stride) const unsigned cbStride = FreeImage_GetPitch(dib); // decode and copy bits to dst array error_code = pDecoder->Copy(pDecoder, &rect, dib_bits, cbStride); JXR_CHECK(error_code); } else { // we need to use the conversion API ... // allocate the pixel format converter error_code = PKCodecFactory_CreateFormatConverter(&pConverter); JXR_CHECK(error_code); // set the conversion function error_code = pConverter->Initialize(pConverter, pDecoder, NULL, out_guid_format); JXR_CHECK(error_code); // get the maximum stride unsigned cbStride = 0; { PKPixelInfo pPIFrom; PKPixelInfo pPITo; pPIFrom.pGUIDPixFmt = &in_guid_format; error_code = PixelFormatLookup(&pPIFrom, LOOKUP_FORWARD); JXR_CHECK(error_code); pPITo.pGUIDPixFmt = &out_guid_format; error_code = PixelFormatLookup(&pPITo, LOOKUP_FORWARD); JXR_CHECK(error_code); unsigned cbStrideFrom = ((pPIFrom.cbitUnit + 7) >> 3) * width; unsigned cbStrideTo = ((pPITo.cbitUnit + 7) >> 3) * width; cbStride = MAX(cbStrideFrom, cbStrideTo); } // allocate a local decoder / encoder buffer error_code = PKAllocAligned((void **) &pb, cbStride * height, 128); JXR_CHECK(error_code); // copy / convert pixels error_code = pConverter->Copy(pConverter, &rect, pb, cbStride); JXR_CHECK(error_code); // now copy pixels into the dib const size_t line_size = FreeImage_GetLine(dib); for(int y = 0; y < height; y++) { BYTE *src_bits = (BYTE*)(pb + y * cbStride); BYTE *dst_bits = (BYTE*)FreeImage_GetScanLine(dib, y); memcpy(dst_bits, src_bits, line_size); } // free the local buffer PKFreeAligned((void **) &pb); // free the pixel format converter PKFormatConverter_Release(&pConverter); } // FreeImage DIB are upside-down relative to usual graphic conventions FreeImage_FlipVertical(dib); // post-processing ... // ------------------- // swap RGB as needed #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR if(IsEqualGUID(out_guid_format, GUID_PKPixelFormat24bppRGB) || IsEqualGUID(out_guid_format, GUID_PKPixelFormat32bppRGB)) { SwapRedBlue32(dib); } #elif FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB if(IsEqualGUID(out_guid_format, GUID_PKPixelFormat24bppBGR) || IsEqualGUID(out_guid_format, GUID_PKPixelFormat32bppBGR)) { SwapRedBlue32(dib); } #endif return WMP_errSuccess; } catch(...) { // free the local buffer PKFreeAligned((void **) &pb); // free the pixel format converter PKFormatConverter_Release(&pConverter); return error_code; } }