| // ========================================================== |
| // Copy / paste routines |
| // |
| // - Floris van den Berg (flvdberg@wxs.nl) |
| // - Alexander Dymerets (sashad@te.net.ua) |
| // - Hervé Drolon (drolon@infonie.fr) |
| // - Manfred Tausch (manfred.tausch@t-online.de) |
| // - Riley McNiff (rmcniff@marexgroup.com) |
| // - Carsten Klein (cklein05@users.sourceforge.net) |
| // |
| // This file is part of FreeImage 3 |
| // |
| // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY |
| // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES |
| // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE |
| // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED |
| // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT |
| // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY |
| // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL |
| // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER |
| // THIS DISCLAIMER. |
| // |
| // Use at your own risk! |
| // ========================================================== |
| |
| #include "FreeImage.h" |
| #include "Utilities.h" |
| |
| // ---------------------------------------------------------- |
| // Helpers |
| // ---------------------------------------------------------- |
| |
| ///////////////////////////////////////////////////////////// |
| // Alpha blending / combine functions |
| |
| // ---------------------------------------------------------- |
| /// 1-bit |
| static BOOL Combine1(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha); |
| /// 4-bit |
| static BOOL Combine4(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha); |
| /// 8-bit |
| static BOOL Combine8(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha); |
| /// 16-bit 555 |
| static BOOL Combine16_555(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha); |
| /// 16-bit 565 |
| static BOOL Combine16_565(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha); |
| /// 24-bit |
| static BOOL Combine24(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha); |
| /// 32- bit |
| static BOOL Combine32(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha); |
| // ---------------------------------------------------------- |
| |
| // ---------------------------------------------------------- |
| // 1-bit |
| // ---------------------------------------------------------- |
| |
| static BOOL |
| Combine1(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) { |
| BOOL value; |
| |
| // check the bit depth of src and dst images |
| if((FreeImage_GetBPP(dst_dib) != 1) || (FreeImage_GetBPP(src_dib) != 1)) { |
| return FALSE; |
| } |
| |
| // check the size of src image |
| if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) { |
| return FALSE; |
| } |
| |
| BYTE *dst_bits = FreeImage_GetBits(dst_dib) + ((FreeImage_GetHeight(dst_dib) - FreeImage_GetHeight(src_dib) - y) * FreeImage_GetPitch(dst_dib)); |
| BYTE *src_bits = FreeImage_GetBits(src_dib); |
| |
| // combine images |
| for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) { |
| for(unsigned cols = 0; cols < FreeImage_GetWidth(src_dib); cols++) { |
| // get bit at (rows, cols) in src image |
| value = (src_bits[cols >> 3] & (0x80 >> (cols & 0x07))) != 0; |
| // set bit at (rows, x+cols) in dst image |
| value ? dst_bits[(x + cols) >> 3] |= (0x80 >> ((x + cols) & 0x7)) : dst_bits[(x + cols) >> 3] &= (0xFF7F >> ((x + cols) & 0x7)); |
| } |
| |
| dst_bits += FreeImage_GetPitch(dst_dib); |
| src_bits += FreeImage_GetPitch(src_dib); |
| } |
| |
| return TRUE; |
| } |
| |
| // ---------------------------------------------------------- |
| // 4-bit |
| // ---------------------------------------------------------- |
| |
| static BOOL |
| Combine4(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) { |
| int swapTable[16]; |
| BOOL bOddStart, bOddEnd; |
| |
| // check the bit depth of src and dst images |
| if((FreeImage_GetBPP(dst_dib) != 4) || (FreeImage_GetBPP(src_dib) != 4)) { |
| return FALSE; |
| } |
| |
| // check the size of src image |
| if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) { |
| return FALSE; |
| } |
| |
| // get src and dst palettes |
| RGBQUAD *src_pal = FreeImage_GetPalette(src_dib); |
| RGBQUAD *dst_pal = FreeImage_GetPalette(dst_dib); |
| if (src_pal == NULL || dst_pal == NULL) { |
| return FALSE; |
| } |
| |
| // build a swap table for the closest color match from the source palette to the destination palette |
| |
| for (int i = 0; i < 16; i++) { |
| WORD min_diff = (WORD)-1; |
| |
| for (int j = 0; j < 16; j++) { |
| // calculates the color difference using a Manhattan distance |
| WORD abs_diff = (WORD)( |
| abs(src_pal[i].rgbBlue - dst_pal[j].rgbBlue) |
| + abs(src_pal[i].rgbGreen - dst_pal[j].rgbGreen) |
| + abs(src_pal[i].rgbRed - dst_pal[j].rgbRed) |
| ); |
| |
| if (abs_diff < min_diff) { |
| swapTable[i] = j; |
| min_diff = abs_diff; |
| if (abs_diff == 0) { |
| break; |
| } |
| } |
| } |
| } |
| |
| BYTE *dst_bits = FreeImage_GetBits(dst_dib) + ((FreeImage_GetHeight(dst_dib) - FreeImage_GetHeight(src_dib) - y) * FreeImage_GetPitch(dst_dib)) + (x >> 1); |
| BYTE *src_bits = FreeImage_GetBits(src_dib); |
| |
| // combine images |
| |
| // allocate space for our temporary row |
| unsigned src_line = FreeImage_GetLine(src_dib); |
| unsigned src_width = FreeImage_GetWidth(src_dib); |
| unsigned src_height = FreeImage_GetHeight(src_dib); |
| |
| BYTE *buffer = (BYTE *)malloc(src_line * sizeof(BYTE)); |
| if (buffer == NULL) { |
| return FALSE; |
| } |
| |
| bOddStart = (x & 0x01) ? TRUE : FALSE; |
| |
| if ((bOddStart && !(src_width & 0x01)) || (!bOddStart && (src_width & 0x01))) { |
| bOddEnd = TRUE; |
| } |
| else { |
| bOddEnd = FALSE; |
| } |
| |
| for(unsigned rows = 0; rows < src_height; rows++) { |
| memcpy(buffer, src_bits, src_line); |
| |
| // change the values in the temp row to be those from the swap table |
| |
| for (unsigned cols = 0; cols < src_line; cols++) { |
| buffer[cols] = (BYTE)((swapTable[HINIBBLE(buffer[cols]) >> 4] << 4) + swapTable[LOWNIBBLE(buffer[cols])]); |
| } |
| |
| if (bOddStart) { |
| buffer[0] = HINIBBLE(dst_bits[0]) + LOWNIBBLE(buffer[0]); |
| } |
| |
| if (bOddEnd) { |
| buffer[src_line - 1] = HINIBBLE(buffer[src_line - 1]) + LOWNIBBLE(dst_bits[src_line - 1]); |
| } |
| |
| memcpy(dst_bits, buffer, src_line); |
| |
| dst_bits += FreeImage_GetPitch(dst_dib); |
| src_bits += FreeImage_GetPitch(src_dib); |
| } |
| |
| free(buffer); |
| |
| return TRUE; |
| |
| } |
| |
| // ---------------------------------------------------------- |
| // 8-bit |
| // ---------------------------------------------------------- |
| |
| static BOOL |
| Combine8(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) { |
| // check the bit depth of src and dst images |
| if((FreeImage_GetBPP(dst_dib) != 8) || (FreeImage_GetBPP(src_dib) != 8)) { |
| return FALSE; |
| } |
| |
| // check the size of src image |
| if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) { |
| return FALSE; |
| } |
| |
| BYTE *dst_bits = FreeImage_GetBits(dst_dib) + ((FreeImage_GetHeight(dst_dib) - FreeImage_GetHeight(src_dib) - y) * FreeImage_GetPitch(dst_dib)) + (x); |
| BYTE *src_bits = FreeImage_GetBits(src_dib); |
| |
| if(alpha > 255) { |
| // combine images |
| for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) { |
| memcpy(dst_bits, src_bits, FreeImage_GetLine(src_dib)); |
| |
| dst_bits += FreeImage_GetPitch(dst_dib); |
| src_bits += FreeImage_GetPitch(src_dib); |
| } |
| } else { |
| // alpha blend images |
| for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) { |
| for (unsigned cols = 0; cols < FreeImage_GetLine(src_dib); cols++) { |
| dst_bits[cols] = (BYTE)(((src_bits[cols] - dst_bits[cols]) * alpha + (dst_bits[cols] << 8)) >> 8); |
| } |
| |
| dst_bits += FreeImage_GetPitch(dst_dib); |
| src_bits += FreeImage_GetPitch(src_dib); |
| } |
| } |
| |
| return TRUE; |
| } |
| |
| // ---------------------------------------------------------- |
| // 16-bit |
| // ---------------------------------------------------------- |
| |
| static BOOL |
| Combine16_555(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) { |
| // check the bit depth of src and dst images |
| if((FreeImage_GetBPP(dst_dib) != 16) || (FreeImage_GetBPP(src_dib) != 16)) { |
| return FALSE; |
| } |
| |
| // check the size of src image |
| if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) { |
| return FALSE; |
| } |
| |
| BYTE *dst_bits = FreeImage_GetBits(dst_dib) + ((FreeImage_GetHeight(dst_dib) - FreeImage_GetHeight(src_dib) - y) * FreeImage_GetPitch(dst_dib)) + (x * 2); |
| BYTE *src_bits = FreeImage_GetBits(src_dib); |
| |
| if (alpha > 255) { |
| for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) { |
| memcpy(dst_bits, src_bits, FreeImage_GetLine(src_dib)); |
| |
| dst_bits += FreeImage_GetPitch(dst_dib); |
| src_bits += FreeImage_GetPitch(src_dib); |
| } |
| } else { |
| for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) { |
| for(unsigned cols = 0; cols < FreeImage_GetLine(src_dib); cols += 2) { |
| RGBTRIPLE color_s; |
| RGBTRIPLE color_t; |
| |
| WORD *tmp1 = (WORD *)&dst_bits[cols]; |
| WORD *tmp2 = (WORD *)&src_bits[cols]; |
| |
| // convert 16-bit colors to 24-bit |
| |
| color_s.rgbtRed = (BYTE)(((*tmp1 & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) << 3); |
| color_s.rgbtGreen = (BYTE)(((*tmp1 & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) << 3); |
| color_s.rgbtBlue = (BYTE)(((*tmp1 & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) << 3); |
| |
| color_t.rgbtRed = (BYTE)(((*tmp2 & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) << 3); |
| color_t.rgbtGreen = (BYTE)(((*tmp2 & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) << 3); |
| color_t.rgbtBlue = (BYTE)(((*tmp2 & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) << 3); |
| |
| // alpha blend |
| |
| color_s.rgbtRed = (BYTE)(((color_t.rgbtRed - color_s.rgbtRed) * alpha + (color_s.rgbtRed << 8)) >> 8); |
| color_s.rgbtGreen = (BYTE)(((color_t.rgbtGreen - color_s.rgbtGreen) * alpha + (color_s.rgbtGreen << 8)) >> 8); |
| color_s.rgbtBlue = (BYTE)(((color_t.rgbtBlue - color_s.rgbtBlue) * alpha + (color_s.rgbtBlue << 8)) >> 8); |
| |
| // convert 24-bit color back to 16-bit |
| |
| *tmp1 = RGB555(color_s.rgbtRed, color_s.rgbtGreen, color_s.rgbtBlue); |
| } |
| |
| dst_bits += FreeImage_GetPitch(dst_dib); |
| src_bits += FreeImage_GetPitch(src_dib); |
| } |
| } |
| |
| return TRUE; |
| } |
| |
| static BOOL |
| Combine16_565(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) { |
| // check the bit depth of src and dst images |
| if((FreeImage_GetBPP(dst_dib) != 16) || (FreeImage_GetBPP(src_dib) != 16)) { |
| return FALSE; |
| } |
| |
| // check the size of src image |
| if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) { |
| return FALSE; |
| } |
| |
| BYTE *dst_bits = FreeImage_GetBits(dst_dib) + ((FreeImage_GetHeight(dst_dib) - FreeImage_GetHeight(src_dib) - y) * FreeImage_GetPitch(dst_dib)) + (x * 2); |
| BYTE *src_bits = FreeImage_GetBits(src_dib); |
| |
| if (alpha > 255) { |
| for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) { |
| memcpy(dst_bits, src_bits, FreeImage_GetLine(src_dib)); |
| |
| dst_bits += FreeImage_GetPitch(dst_dib); |
| src_bits += FreeImage_GetPitch(src_dib); |
| } |
| } else { |
| for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) { |
| for(unsigned cols = 0; cols < FreeImage_GetLine(src_dib); cols += 2) { |
| RGBTRIPLE color_s; |
| RGBTRIPLE color_t; |
| |
| WORD *tmp1 = (WORD *)&dst_bits[cols]; |
| WORD *tmp2 = (WORD *)&src_bits[cols]; |
| |
| // convert 16-bit colors to 24-bit |
| |
| color_s.rgbtRed = (BYTE)(((*tmp1 & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) << 3); |
| color_s.rgbtGreen = (BYTE)(((*tmp1 & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) << 2); |
| color_s.rgbtBlue = (BYTE)(((*tmp1 & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) << 3); |
| |
| color_t.rgbtRed = (BYTE)(((*tmp2 & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) << 3); |
| color_t.rgbtGreen = (BYTE)(((*tmp2 & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) << 2); |
| color_t.rgbtBlue = (BYTE)(((*tmp2 & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) << 3); |
| |
| // alpha blend |
| |
| color_s.rgbtRed = (BYTE)(((color_t.rgbtRed - color_s.rgbtRed) * alpha + (color_s.rgbtRed << 8)) >> 8); |
| color_s.rgbtGreen = (BYTE)(((color_t.rgbtGreen - color_s.rgbtGreen) * alpha + (color_s.rgbtGreen << 8)) >> 8); |
| color_s.rgbtBlue = (BYTE)(((color_t.rgbtBlue - color_s.rgbtBlue) * alpha + (color_s.rgbtBlue << 8)) >> 8); |
| |
| // convert 24-bit color back to 16-bit |
| |
| *tmp1 = RGB565(color_s.rgbtRed, color_s.rgbtGreen, color_s.rgbtBlue); |
| } |
| |
| dst_bits += FreeImage_GetPitch(dst_dib); |
| src_bits += FreeImage_GetPitch(src_dib); |
| } |
| } |
| |
| return TRUE; |
| } |
| |
| // ---------------------------------------------------------- |
| // 24-bit |
| // ---------------------------------------------------------- |
| |
| static BOOL |
| Combine24(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) { |
| // check the bit depth of src and dst images |
| if((FreeImage_GetBPP(dst_dib) != 24) || (FreeImage_GetBPP(src_dib) != 24)) { |
| return FALSE; |
| } |
| |
| // check the size of src image |
| if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) { |
| return FALSE; |
| } |
| |
| BYTE *dst_bits = FreeImage_GetBits(dst_dib) + ((FreeImage_GetHeight(dst_dib) - FreeImage_GetHeight(src_dib) - y) * FreeImage_GetPitch(dst_dib)) + (x * 3); |
| BYTE *src_bits = FreeImage_GetBits(src_dib); |
| |
| if(alpha > 255) { |
| // combine images |
| for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) { |
| memcpy(dst_bits, src_bits, FreeImage_GetLine(src_dib)); |
| |
| dst_bits += FreeImage_GetPitch(dst_dib); |
| src_bits += FreeImage_GetPitch(src_dib); |
| } |
| } else { |
| // alpha blend images |
| for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) { |
| for (unsigned cols = 0; cols < FreeImage_GetLine(src_dib); cols++) { |
| dst_bits[cols] = (BYTE)(((src_bits[cols] - dst_bits[cols]) * alpha + (dst_bits[cols] << 8)) >> 8); |
| } |
| |
| dst_bits += FreeImage_GetPitch(dst_dib); |
| src_bits += FreeImage_GetPitch(src_dib); |
| } |
| } |
| |
| return TRUE; |
| } |
| |
| // ---------------------------------------------------------- |
| // 32-bit |
| // ---------------------------------------------------------- |
| |
| static BOOL |
| Combine32(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) { |
| // check the bit depth of src and dst images |
| if((FreeImage_GetBPP(dst_dib) != 32) || (FreeImage_GetBPP(src_dib) != 32)) { |
| return FALSE; |
| } |
| |
| // check the size of src image |
| if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) { |
| return FALSE; |
| } |
| |
| BYTE *dst_bits = FreeImage_GetBits(dst_dib) + ((FreeImage_GetHeight(dst_dib) - FreeImage_GetHeight(src_dib) - y) * FreeImage_GetPitch(dst_dib)) + (x * 4); |
| BYTE *src_bits = FreeImage_GetBits(src_dib); |
| |
| if (alpha > 255) { |
| // combine images |
| for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) { |
| memcpy(dst_bits, src_bits, FreeImage_GetLine(src_dib)); |
| |
| dst_bits += FreeImage_GetPitch(dst_dib); |
| src_bits += FreeImage_GetPitch(src_dib); |
| } |
| } else { |
| // alpha blend images |
| for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) { |
| for(unsigned cols = 0; cols < FreeImage_GetLine(src_dib); cols++) { |
| dst_bits[cols] = (BYTE)(((src_bits[cols] - dst_bits[cols]) * alpha + (dst_bits[cols] << 8)) >> 8); |
| } |
| |
| dst_bits += FreeImage_GetPitch(dst_dib); |
| src_bits += FreeImage_GetPitch(src_dib); |
| } |
| } |
| |
| return TRUE; |
| } |
| |
| // ---------------------------------------------------------- |
| // Any type other than FIBITMAP |
| // ---------------------------------------------------------- |
| |
| static BOOL |
| CombineSameType(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y) { |
| // check the bit depth of src and dst images |
| if(FreeImage_GetImageType(dst_dib) != FreeImage_GetImageType(src_dib)) { |
| return FALSE; |
| } |
| |
| unsigned src_width = FreeImage_GetWidth(src_dib); |
| unsigned src_height = FreeImage_GetHeight(src_dib); |
| unsigned src_pitch = FreeImage_GetPitch(src_dib); |
| unsigned src_line = FreeImage_GetLine(src_dib); |
| unsigned dst_width = FreeImage_GetWidth(dst_dib); |
| unsigned dst_height = FreeImage_GetHeight(dst_dib); |
| unsigned dst_pitch = FreeImage_GetPitch(dst_dib); |
| |
| // check the size of src image |
| if((x + src_width > dst_width) || (y + src_height > dst_height)) { |
| return FALSE; |
| } |
| |
| BYTE *dst_bits = FreeImage_GetBits(dst_dib) + ((dst_height - src_height - y) * dst_pitch) + (x * (src_line / src_width)); |
| BYTE *src_bits = FreeImage_GetBits(src_dib); |
| |
| // combine images |
| for(unsigned rows = 0; rows < src_height; rows++) { |
| memcpy(dst_bits, src_bits, src_line); |
| |
| dst_bits += dst_pitch; |
| src_bits += src_pitch; |
| } |
| |
| return TRUE; |
| } |
| |
| // ---------------------------------------------------------- |
| // FreeImage interface |
| // ---------------------------------------------------------- |
| |
| /** |
| Copy a sub part of the current image and returns it as a FIBITMAP*. |
| Works with any bitmap type. |
| @param left Specifies the left position of the cropped rectangle. |
| @param top Specifies the top position of the cropped rectangle. |
| @param right Specifies the right position of the cropped rectangle. |
| @param bottom Specifies the bottom position of the cropped rectangle. |
| @return Returns the subimage if successful, NULL otherwise. |
| */ |
| FIBITMAP * DLL_CALLCONV |
| FreeImage_Copy(FIBITMAP *src, int left, int top, int right, int bottom) { |
| |
| if(!FreeImage_HasPixels(src)) |
| 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); |
| if((left < 0) || (right > src_width) || (top < 0) || (bottom > src_height)) { |
| return NULL; |
| } |
| |
| // allocate the sub image |
| unsigned bpp = FreeImage_GetBPP(src); |
| int dst_width = (right - left); |
| int dst_height = (bottom - top); |
| |
| FIBITMAP *dst = |
| FreeImage_AllocateT(FreeImage_GetImageType(src), |
| dst_width, |
| dst_height, |
| bpp, |
| FreeImage_GetRedMask(src), FreeImage_GetGreenMask(src), FreeImage_GetBlueMask(src)); |
| |
| if(NULL == dst) return NULL; |
| |
| // get the dimensions |
| int dst_line = FreeImage_GetLine(dst); |
| int dst_pitch = FreeImage_GetPitch(dst); |
| int src_pitch = FreeImage_GetPitch(src); |
| |
| // get the pointers to the bits and such |
| |
| BYTE *src_bits = FreeImage_GetScanLine(src, src_height - top - dst_height); |
| switch(bpp) { |
| case 1: |
| // point to x = 0 |
| break; |
| |
| case 4: |
| // point to x = 0 |
| break; |
| |
| default: |
| { |
| // calculate the number of bytes per pixel |
| unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src); |
| // point to x = left |
| src_bits += left * bytespp; |
| } |
| break; |
| } |
| |
| // point to x = 0 |
| BYTE *dst_bits = FreeImage_GetBits(dst); |
| |
| // copy the palette |
| |
| memcpy(FreeImage_GetPalette(dst), FreeImage_GetPalette(src), FreeImage_GetColorsUsed(src) * sizeof(RGBQUAD)); |
| |
| // copy the bits |
| if(bpp == 1) { |
| BOOL value; |
| unsigned y_src, y_dst; |
| |
| for(int y = 0; y < dst_height; y++) { |
| y_src = y * src_pitch; |
| y_dst = y * dst_pitch; |
| for(int x = 0; x < dst_width; x++) { |
| // get bit at (y, x) in src image |
| value = (src_bits[y_src + ((left+x) >> 3)] & (0x80 >> ((left+x) & 0x07))) != 0; |
| // set bit at (y, x) in dst image |
| value ? dst_bits[y_dst + (x >> 3)] |= (0x80 >> (x & 0x7)) : dst_bits[y_dst + (x >> 3)] &= (0xff7f >> (x & 0x7)); |
| } |
| } |
| } |
| |
| else if(bpp == 4) { |
| BYTE shift, value; |
| unsigned y_src, y_dst; |
| |
| for(int y = 0; y < dst_height; y++) { |
| y_src = y * src_pitch; |
| y_dst = y * dst_pitch; |
| for(int x = 0; x < dst_width; x++) { |
| // get nibble at (y, x) in src image |
| shift = (BYTE)((1 - (left+x) % 2) << 2); |
| value = (src_bits[y_src + ((left+x) >> 1)] & (0x0F << shift)) >> shift; |
| // set nibble at (y, x) in dst image |
| shift = (BYTE)((1 - x % 2) << 2); |
| dst_bits[y_dst + (x >> 1)] &= ~(0x0F << shift); |
| dst_bits[y_dst + (x >> 1)] |= ((value & 0x0F) << shift); |
| } |
| } |
| } |
| |
| else if(bpp >= 8) { |
| for(int y = 0; y < dst_height; y++) { |
| memcpy(dst_bits + (y * dst_pitch), src_bits + (y * src_pitch), dst_line); |
| } |
| } |
| |
| // copy metadata from src to dst |
| FreeImage_CloneMetadata(dst, src); |
| |
| // copy transparency table |
| FreeImage_SetTransparencyTable(dst, FreeImage_GetTransparencyTable(src), FreeImage_GetTransparencyCount(src)); |
| |
| // copy background color |
| RGBQUAD bkcolor; |
| if( FreeImage_GetBackgroundColor(src, &bkcolor) ) { |
| FreeImage_SetBackgroundColor(dst, &bkcolor); |
| } |
| |
| // clone resolution |
| FreeImage_SetDotsPerMeterX(dst, FreeImage_GetDotsPerMeterX(src)); |
| FreeImage_SetDotsPerMeterY(dst, FreeImage_GetDotsPerMeterY(src)); |
| |
| // clone ICC profile |
| FIICCPROFILE *src_profile = FreeImage_GetICCProfile(src); |
| FIICCPROFILE *dst_profile = FreeImage_CreateICCProfile(dst, src_profile->data, src_profile->size); |
| dst_profile->flags = src_profile->flags; |
| |
| return dst; |
| } |
| |
| /** |
| Alpha blend or combine a sub part image with the current image. |
| The bit depth of dst bitmap must be greater than or equal to the bit depth of src. |
| Upper promotion of src is done internally. Supported bit depth equals to 1, 4, 8, 16, 24 or 32. |
| @param src Source subimage |
| @param left Specifies the left position of the sub image. |
| @param top Specifies the top position of the sub image. |
| @param alpha Alpha blend factor. The source and destination images are alpha blended if |
| alpha = 0..255. If alpha > 255, then the source image is combined to the destination image. |
| @return Returns TRUE if successful, FALSE otherwise. |
| */ |
| BOOL DLL_CALLCONV |
| FreeImage_Paste(FIBITMAP *dst, FIBITMAP *src, int left, int top, int alpha) { |
| BOOL bResult = FALSE; |
| |
| if(!FreeImage_HasPixels(src) || !FreeImage_HasPixels(dst)) return FALSE; |
| |
| // check the size of src image |
| if((left < 0) || (top < 0)) { |
| return FALSE; |
| } |
| if((left + FreeImage_GetWidth(src) > FreeImage_GetWidth(dst)) || (top + FreeImage_GetHeight(src) > FreeImage_GetHeight(dst))) { |
| return FALSE; |
| } |
| |
| // check data type |
| const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dst); |
| if(image_type != FreeImage_GetImageType(src)) { |
| // no conversion between data type is done |
| return FALSE; |
| } |
| |
| if(image_type == FIT_BITMAP) { |
| FIBITMAP *clone = NULL; |
| |
| // check the bit depth of src and dst images |
| unsigned bpp_src = FreeImage_GetBPP(src); |
| unsigned bpp_dst = FreeImage_GetBPP(dst); |
| BOOL isRGB565 = FALSE; |
| |
| if ((FreeImage_GetRedMask(dst) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dst) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dst) == FI16_565_BLUE_MASK)) { |
| isRGB565 = TRUE; |
| } else { |
| // includes case where all the masks are 0 |
| isRGB565 = FALSE; |
| } |
| |
| // perform promotion if needed |
| if(bpp_dst == bpp_src) { |
| clone = src; |
| } else if(bpp_dst > bpp_src) { |
| // perform promotion |
| switch(bpp_dst) { |
| case 4: |
| clone = FreeImage_ConvertTo4Bits(src); |
| break; |
| case 8: |
| clone = FreeImage_ConvertTo8Bits(src); |
| break; |
| case 16: |
| if (isRGB565) { |
| clone = FreeImage_ConvertTo16Bits565(src); |
| } else { |
| // includes case where all the masks are 0 |
| clone = FreeImage_ConvertTo16Bits555(src); |
| } |
| break; |
| case 24: |
| clone = FreeImage_ConvertTo24Bits(src); |
| break; |
| case 32: |
| clone = FreeImage_ConvertTo32Bits(src); |
| break; |
| default: |
| return FALSE; |
| } |
| } else { |
| return FALSE; |
| } |
| |
| if(!clone) return FALSE; |
| |
| // paste src to dst |
| switch(FreeImage_GetBPP(dst)) { |
| case 1: |
| bResult = Combine1(dst, clone, (unsigned)left, (unsigned)top, (unsigned)alpha); |
| break; |
| case 4: |
| bResult = Combine4(dst, clone, (unsigned)left, (unsigned)top, (unsigned)alpha); |
| break; |
| case 8: |
| bResult = Combine8(dst, clone, (unsigned)left, (unsigned)top, (unsigned)alpha); |
| break; |
| case 16: |
| if (isRGB565) { |
| bResult = Combine16_565(dst, clone, (unsigned)left, (unsigned)top, (unsigned)alpha); |
| } else { |
| // includes case where all the masks are 0 |
| bResult = Combine16_555(dst, clone, (unsigned)left, (unsigned)top, (unsigned)alpha); |
| } |
| break; |
| case 24: |
| bResult = Combine24(dst, clone, (unsigned)left, (unsigned)top, (unsigned)alpha); |
| break; |
| case 32: |
| bResult = Combine32(dst, clone, (unsigned)left, (unsigned)top, (unsigned)alpha); |
| break; |
| } |
| |
| if(clone != src) |
| FreeImage_Unload(clone); |
| |
| } |
| else { // any type other than FITBITMAP |
| bResult = CombineSameType(dst, src, (unsigned)left, (unsigned)top); |
| } |
| |
| return bResult; |
| } |
| |
| // ---------------------------------------------------------- |
| |
| /** @brief Creates a dynamic read/write view into a FreeImage bitmap. |
| |
| A dynamic view is a FreeImage bitmap with its own width and height, that, |
| however, shares its bits with another FreeImage bitmap. Typically, views |
| are used to define one or more rectangular sub-images of an existing |
| bitmap. All FreeImage operations, like saving, displaying and all the |
| toolkit functions, when applied to the view, only affect the view's |
| rectangular area. |
| |
| Although the view's backing image's bits not need to be copied around, |
| which makes the view much faster than similar solutions using |
| FreeImage_Copy, a view uses some private memory that needs to be freed by |
| calling FreeImage_Unload on the view's handle to prevent memory leaks. |
| |
| Only the backing image's pixels are shared by the view. For all other image |
| data, notably for the resolution, background color, color palette, |
| transparency table and for the ICC profile, the view gets a private copy |
| of the data. By default, the backing image's metadata is NOT copied to |
| the view. |
| |
| As with all FreeImage functions that take a rectangle region, top and left |
| positions are included, whereas right and bottom positions are excluded |
| from the rectangle area. |
| |
| Since the memory block shared by the backing image and the view must start |
| at a byte boundary, the value of parameter left must be a multiple of 8 |
| for 1-bit images and a multiple of 2 for 4-bit images. |
| |
| @param dib The FreeImage bitmap on which to create the view. |
| @param left The left position of the view's area. |
| @param top The top position of the view's area. |
| @param right The right position of the view's area. |
| @param bottom The bottom position of the view's area. |
| @return Returns a handle to the newly created view or NULL if the view |
| was not created. |
| */ |
| FIBITMAP * DLL_CALLCONV |
| FreeImage_CreateView(FIBITMAP *dib, unsigned left, unsigned top, unsigned right, unsigned bottom) { |
| if (!FreeImage_HasPixels(dib)) { |
| return NULL; |
| } |
| |
| // normalize the rectangle |
| if (right < left) { |
| INPLACESWAP(left, right); |
| } |
| if (bottom < top) { |
| INPLACESWAP(top, bottom); |
| } |
| |
| // check the size of the sub image |
| unsigned width = FreeImage_GetWidth(dib); |
| unsigned height = FreeImage_GetHeight(dib); |
| if (left < 0 || right > width || top < 0 || bottom > height) { |
| return NULL; |
| } |
| |
| unsigned bpp = FreeImage_GetBPP(dib); |
| BYTE *bits = FreeImage_GetScanLine(dib, height - bottom); |
| switch (bpp) { |
| case 1: |
| if (left % 8 != 0) { |
| // view can only start at a byte boundary |
| return NULL; |
| } |
| bits += (left / 8); |
| break; |
| case 4: |
| if (left % 2 != 0) { |
| // view can only start at a byte boundary |
| return NULL; |
| } |
| bits += (left / 2); |
| break; |
| default: |
| bits += left * (bpp / 8); |
| break; |
| } |
| |
| FIBITMAP *dst = FreeImage_AllocateHeaderForBits(bits, FreeImage_GetPitch(dib), FreeImage_GetImageType(dib), |
| right - left, bottom - top, |
| bpp, |
| FreeImage_GetRedMask(dib), FreeImage_GetGreenMask(dib), FreeImage_GetBlueMask(dib)); |
| |
| if (dst == NULL) { |
| return NULL; |
| } |
| |
| // copy some basic image properties needed for displaying and saving |
| |
| // resolution |
| FreeImage_SetDotsPerMeterX(dst, FreeImage_GetDotsPerMeterX(dib)); |
| FreeImage_SetDotsPerMeterY(dst, FreeImage_GetDotsPerMeterY(dib)); |
| |
| // background color |
| RGBQUAD bkcolor; |
| if (FreeImage_GetBackgroundColor(dib, &bkcolor)) { |
| FreeImage_SetBackgroundColor(dst, &bkcolor); |
| } |
| |
| // palette |
| memcpy(FreeImage_GetPalette(dst), FreeImage_GetPalette(dib), FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD)); |
| |
| // transparency table |
| FreeImage_SetTransparencyTable(dst, FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib)); |
| |
| // ICC profile |
| FIICCPROFILE *src_profile = FreeImage_GetICCProfile(dib); |
| FIICCPROFILE *dst_profile = FreeImage_CreateICCProfile(dst, src_profile->data, src_profile->size); |
| dst_profile->flags = src_profile->flags; |
| |
| return dst; |
| } |