summaryrefslogtreecommitdiff
path: root/plugins/FreeImage/Source/FreeImageToolkit/CopyPaste.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/FreeImage/Source/FreeImageToolkit/CopyPaste.cpp')
-rw-r--r--plugins/FreeImage/Source/FreeImageToolkit/CopyPaste.cpp747
1 files changed, 747 insertions, 0 deletions
diff --git a/plugins/FreeImage/Source/FreeImageToolkit/CopyPaste.cpp b/plugins/FreeImage/Source/FreeImageToolkit/CopyPaste.cpp
new file mode 100644
index 0000000000..b66efbf9e8
--- /dev/null
+++ b/plugins/FreeImage/Source/FreeImageToolkit/CopyPaste.cpp
@@ -0,0 +1,747 @@
+// ==========================================================
+// 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)
+//
+// 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;
+}
+
+