1 // ==========================================================
2 // Copy / paste routines
3 //
4 // - Floris van den Berg (flvdberg@wxs.nl)
5 // - Alexander Dymerets (sashad@te.net.ua)
6 // - Herv� Drolon (drolon@infonie.fr)
7 // - Manfred Tausch (manfred.tausch@t-online.de)
8 // - Riley McNiff (rmcniff@marexgroup.com)
9 // - Carsten Klein (cklein05@users.sourceforge.net)
10 //
11 // This file is part of FreeImage 3
12 //
13 // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
14 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
15 // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
16 // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
17 // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
18 // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
19 // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
20 // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
21 // THIS DISCLAIMER.
22 //
23 // Use at your own risk!
24 // ==========================================================
25 
26 #include "FreeImage.h"
27 #include "Utilities.h"
28 
29 // ----------------------------------------------------------
30 //   Helpers
31 // ----------------------------------------------------------
32 
33 /////////////////////////////////////////////////////////////
34 // Alpha blending / combine functions
35 
36 // ----------------------------------------------------------
37 /// 1-bit
38 static BOOL Combine1(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha);
39 /// 4-bit
40 static BOOL Combine4(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha);
41 /// 8-bit
42 static BOOL Combine8(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha);
43 /// 16-bit 555
44 static BOOL Combine16_555(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha);
45 /// 16-bit 565
46 static BOOL Combine16_565(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha);
47 /// 24-bit
48 static BOOL Combine24(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha);
49 /// 32- bit
50 static BOOL Combine32(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha);
51 // ----------------------------------------------------------
52 
53 // ----------------------------------------------------------
54 //   1-bit
55 // ----------------------------------------------------------
56 
57 static BOOL
Combine1(FIBITMAP * dst_dib,FIBITMAP * src_dib,unsigned x,unsigned y,unsigned alpha)58 Combine1(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) {
59 	BOOL value;
60 
61 	// check the bit depth of src and dst images
62 	if((FreeImage_GetBPP(dst_dib) != 1) || (FreeImage_GetBPP(src_dib) != 1)) {
63 		return FALSE;
64 	}
65 
66 	// check the size of src image
67 	if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
68 		return FALSE;
69 	}
70 
71 	BYTE *dst_bits = FreeImage_GetBits(dst_dib) + ((FreeImage_GetHeight(dst_dib) - FreeImage_GetHeight(src_dib) - y) * FreeImage_GetPitch(dst_dib));
72 	BYTE *src_bits = FreeImage_GetBits(src_dib);
73 
74 	// combine images
75 	for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) {
76 		for(unsigned cols = 0; cols < FreeImage_GetWidth(src_dib); cols++) {
77 			// get bit at (rows, cols) in src image
78 			value = (src_bits[cols >> 3] & (0x80 >> (cols & 0x07))) != 0;
79 			// set bit at (rows, x+cols) in dst image
80 			value ? dst_bits[(x + cols) >> 3] |= (0x80 >> ((x + cols) & 0x7)) : dst_bits[(x + cols) >> 3] &= (0xFF7F >> ((x + cols) & 0x7));
81 		}
82 
83 		dst_bits += FreeImage_GetPitch(dst_dib);
84 		src_bits += FreeImage_GetPitch(src_dib);
85 	}
86 
87 	return TRUE;
88 }
89 
90 // ----------------------------------------------------------
91 //   4-bit
92 // ----------------------------------------------------------
93 
94 static BOOL
Combine4(FIBITMAP * dst_dib,FIBITMAP * src_dib,unsigned x,unsigned y,unsigned alpha)95 Combine4(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) {
96 	int swapTable[16];
97 	BOOL bOddStart, bOddEnd;
98 
99 	// check the bit depth of src and dst images
100 	if((FreeImage_GetBPP(dst_dib) != 4) || (FreeImage_GetBPP(src_dib) != 4)) {
101 		return FALSE;
102 	}
103 
104 	// check the size of src image
105 	if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
106 		return FALSE;
107 	}
108 
109 	// get src and dst palettes
110 	RGBQUAD *src_pal = FreeImage_GetPalette(src_dib);
111 	RGBQUAD *dst_pal = FreeImage_GetPalette(dst_dib);
112 	if (src_pal == NULL || dst_pal == NULL) {
113 		return FALSE;
114 	}
115 
116 	// build a swap table for the closest color match from the source palette to the destination palette
117 
118 	for (int i = 0; i < 16; i++)	{
119 		WORD min_diff = (WORD)-1;
120 
121 		for (int j = 0; j < 16; j++)	{
122 			// calculates the color difference using a Manhattan distance
123 			WORD abs_diff = (WORD)(
124 				abs(src_pal[i].rgbBlue - dst_pal[j].rgbBlue)
125 				+ abs(src_pal[i].rgbGreen - dst_pal[j].rgbGreen)
126 				+ abs(src_pal[i].rgbRed - dst_pal[j].rgbRed)
127 				);
128 
129 			if (abs_diff < min_diff)	{
130 				swapTable[i] = j;
131 				min_diff = abs_diff;
132 				if (abs_diff == 0) {
133 					break;
134 				}
135 			}
136 		}
137 	}
138 
139 	BYTE *dst_bits = FreeImage_GetBits(dst_dib) + ((FreeImage_GetHeight(dst_dib) - FreeImage_GetHeight(src_dib) - y) *	FreeImage_GetPitch(dst_dib)) + (x >> 1);
140 	BYTE *src_bits = FreeImage_GetBits(src_dib);
141 
142 	// combine images
143 
144 	// allocate space for our temporary row
145 	unsigned src_line   = FreeImage_GetLine(src_dib);
146 	unsigned src_width  = FreeImage_GetWidth(src_dib);
147 	unsigned src_height = FreeImage_GetHeight(src_dib);
148 
149 	BYTE *buffer = (BYTE *)malloc(src_line * sizeof(BYTE));
150 	if (buffer == NULL) {
151 		return FALSE;
152 	}
153 
154 	bOddStart = (x & 0x01) ? TRUE : FALSE;
155 
156 	if ((bOddStart && !(src_width & 0x01)) || (!bOddStart && (src_width & 0x01)))	{
157 		bOddEnd = TRUE;
158 	}
159 	else {
160 		bOddEnd = FALSE;
161 	}
162 
163 	for(unsigned rows = 0; rows < src_height; rows++) {
164 		memcpy(buffer, src_bits, src_line);
165 
166 		// change the values in the temp row to be those from the swap table
167 
168 		for (unsigned cols = 0; cols < src_line; cols++) {
169 			buffer[cols] = (BYTE)((swapTable[HINIBBLE(buffer[cols]) >> 4] << 4) + swapTable[LOWNIBBLE(buffer[cols])]);
170 		}
171 
172 		if (bOddStart) {
173 			buffer[0] = HINIBBLE(dst_bits[0]) + LOWNIBBLE(buffer[0]);
174 		}
175 
176 		if (bOddEnd)	{
177 			buffer[src_line - 1] = HINIBBLE(buffer[src_line - 1]) + LOWNIBBLE(dst_bits[src_line - 1]);
178 		}
179 
180 		memcpy(dst_bits, buffer, src_line);
181 
182 		dst_bits += FreeImage_GetPitch(dst_dib);
183 		src_bits += FreeImage_GetPitch(src_dib);
184 	}
185 
186 	free(buffer);
187 
188 	return TRUE;
189 
190 }
191 
192 // ----------------------------------------------------------
193 //   8-bit
194 // ----------------------------------------------------------
195 
196 static BOOL
Combine8(FIBITMAP * dst_dib,FIBITMAP * src_dib,unsigned x,unsigned y,unsigned alpha)197 Combine8(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) {
198 	// check the bit depth of src and dst images
199 	if((FreeImage_GetBPP(dst_dib) != 8) || (FreeImage_GetBPP(src_dib) != 8)) {
200 		return FALSE;
201 	}
202 
203 	// check the size of src image
204 	if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
205 		return FALSE;
206 	}
207 
208 	BYTE *dst_bits = FreeImage_GetBits(dst_dib) + ((FreeImage_GetHeight(dst_dib) - FreeImage_GetHeight(src_dib) - y) * FreeImage_GetPitch(dst_dib)) + (x);
209 	BYTE *src_bits = FreeImage_GetBits(src_dib);
210 
211 	if(alpha > 255) {
212 		// combine images
213 		for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) {
214 			memcpy(dst_bits, src_bits, FreeImage_GetLine(src_dib));
215 
216 			dst_bits += FreeImage_GetPitch(dst_dib);
217 			src_bits += FreeImage_GetPitch(src_dib);
218 		}
219 	} else {
220 		// alpha blend images
221 		for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) {
222 			for (unsigned cols = 0; cols < FreeImage_GetLine(src_dib); cols++) {
223 				dst_bits[cols] = (BYTE)(((src_bits[cols] - dst_bits[cols]) * alpha + (dst_bits[cols] << 8)) >> 8);
224 			}
225 
226 			dst_bits += FreeImage_GetPitch(dst_dib);
227 			src_bits += FreeImage_GetPitch(src_dib);
228 		}
229 	}
230 
231 	return TRUE;
232 }
233 
234 // ----------------------------------------------------------
235 //   16-bit
236 // ----------------------------------------------------------
237 
238 static BOOL
Combine16_555(FIBITMAP * dst_dib,FIBITMAP * src_dib,unsigned x,unsigned y,unsigned alpha)239 Combine16_555(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) {
240 	// check the bit depth of src and dst images
241 	if((FreeImage_GetBPP(dst_dib) != 16) || (FreeImage_GetBPP(src_dib) != 16)) {
242 		return FALSE;
243 	}
244 
245 	// check the size of src image
246 	if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
247 		return FALSE;
248 	}
249 
250 	BYTE *dst_bits = FreeImage_GetBits(dst_dib) + ((FreeImage_GetHeight(dst_dib) - FreeImage_GetHeight(src_dib) - y) * FreeImage_GetPitch(dst_dib)) + (x * 2);
251 	BYTE *src_bits = FreeImage_GetBits(src_dib);
252 
253 	if (alpha > 255) {
254 		for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) {
255 			memcpy(dst_bits, src_bits, FreeImage_GetLine(src_dib));
256 
257 			dst_bits += FreeImage_GetPitch(dst_dib);
258 			src_bits += FreeImage_GetPitch(src_dib);
259 		}
260 	} else {
261 		for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) {
262 			for(unsigned cols = 0; cols < FreeImage_GetLine(src_dib); cols += 2) {
263 				RGBTRIPLE color_s;
264 				RGBTRIPLE color_t;
265 
266 				WORD *tmp1 = (WORD *)&dst_bits[cols];
267 				WORD *tmp2 = (WORD *)&src_bits[cols];
268 
269 				// convert 16-bit colors to 24-bit
270 
271 				color_s.rgbtRed = (BYTE)(((*tmp1 & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) << 3);
272 				color_s.rgbtGreen = (BYTE)(((*tmp1 & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) << 3);
273 				color_s.rgbtBlue = (BYTE)(((*tmp1 & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) << 3);
274 
275 				color_t.rgbtRed = (BYTE)(((*tmp2 & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) << 3);
276 				color_t.rgbtGreen = (BYTE)(((*tmp2 & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) << 3);
277 				color_t.rgbtBlue = (BYTE)(((*tmp2 & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) << 3);
278 
279 				// alpha blend
280 
281 				color_s.rgbtRed = (BYTE)(((color_t.rgbtRed - color_s.rgbtRed) * alpha + (color_s.rgbtRed << 8)) >> 8);
282 				color_s.rgbtGreen = (BYTE)(((color_t.rgbtGreen - color_s.rgbtGreen) * alpha + (color_s.rgbtGreen << 8)) >> 8);
283 				color_s.rgbtBlue = (BYTE)(((color_t.rgbtBlue - color_s.rgbtBlue) * alpha + (color_s.rgbtBlue << 8)) >> 8);
284 
285 				// convert 24-bit color back to 16-bit
286 
287 				*tmp1 = RGB555(color_s.rgbtRed, color_s.rgbtGreen, color_s.rgbtBlue);
288 			}
289 
290 			dst_bits += FreeImage_GetPitch(dst_dib);
291 			src_bits += FreeImage_GetPitch(src_dib);
292 		}
293 	}
294 
295 	return TRUE;
296 }
297 
298 static BOOL
Combine16_565(FIBITMAP * dst_dib,FIBITMAP * src_dib,unsigned x,unsigned y,unsigned alpha)299 Combine16_565(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) {
300 	// check the bit depth of src and dst images
301 	if((FreeImage_GetBPP(dst_dib) != 16) || (FreeImage_GetBPP(src_dib) != 16)) {
302 		return FALSE;
303 	}
304 
305 	// check the size of src image
306 	if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
307 		return FALSE;
308 	}
309 
310 	BYTE *dst_bits = FreeImage_GetBits(dst_dib) + ((FreeImage_GetHeight(dst_dib) - FreeImage_GetHeight(src_dib) - y) * FreeImage_GetPitch(dst_dib)) + (x * 2);
311 	BYTE *src_bits = FreeImage_GetBits(src_dib);
312 
313 	if (alpha > 255) {
314 		for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) {
315 			memcpy(dst_bits, src_bits, FreeImage_GetLine(src_dib));
316 
317 			dst_bits += FreeImage_GetPitch(dst_dib);
318 			src_bits += FreeImage_GetPitch(src_dib);
319 		}
320 	} else {
321 		for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) {
322 			for(unsigned cols = 0; cols < FreeImage_GetLine(src_dib); cols += 2) {
323 				RGBTRIPLE color_s;
324 				RGBTRIPLE color_t;
325 
326 				WORD *tmp1 = (WORD *)&dst_bits[cols];
327 				WORD *tmp2 = (WORD *)&src_bits[cols];
328 
329 				// convert 16-bit colors to 24-bit
330 
331 				color_s.rgbtRed = (BYTE)(((*tmp1 & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) << 3);
332 				color_s.rgbtGreen = (BYTE)(((*tmp1 & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) << 2);
333 				color_s.rgbtBlue = (BYTE)(((*tmp1 & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) << 3);
334 
335 				color_t.rgbtRed = (BYTE)(((*tmp2 & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) << 3);
336 				color_t.rgbtGreen = (BYTE)(((*tmp2 & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) << 2);
337 				color_t.rgbtBlue = (BYTE)(((*tmp2 & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) << 3);
338 
339 				// alpha blend
340 
341 				color_s.rgbtRed = (BYTE)(((color_t.rgbtRed - color_s.rgbtRed) * alpha + (color_s.rgbtRed << 8)) >> 8);
342 				color_s.rgbtGreen = (BYTE)(((color_t.rgbtGreen - color_s.rgbtGreen) * alpha + (color_s.rgbtGreen << 8)) >> 8);
343 				color_s.rgbtBlue = (BYTE)(((color_t.rgbtBlue - color_s.rgbtBlue) * alpha + (color_s.rgbtBlue << 8)) >> 8);
344 
345 				// convert 24-bit color back to 16-bit
346 
347 				*tmp1 = RGB565(color_s.rgbtRed, color_s.rgbtGreen, color_s.rgbtBlue);
348 			}
349 
350 			dst_bits += FreeImage_GetPitch(dst_dib);
351 			src_bits += FreeImage_GetPitch(src_dib);
352 		}
353 	}
354 
355 	return TRUE;
356 }
357 
358 // ----------------------------------------------------------
359 //   24-bit
360 // ----------------------------------------------------------
361 
362 static BOOL
Combine24(FIBITMAP * dst_dib,FIBITMAP * src_dib,unsigned x,unsigned y,unsigned alpha)363 Combine24(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) {
364 	// check the bit depth of src and dst images
365 	if((FreeImage_GetBPP(dst_dib) != 24) || (FreeImage_GetBPP(src_dib) != 24)) {
366 		return FALSE;
367 	}
368 
369 	// check the size of src image
370 	if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
371 		return FALSE;
372 	}
373 
374 	BYTE *dst_bits = FreeImage_GetBits(dst_dib) + ((FreeImage_GetHeight(dst_dib) - FreeImage_GetHeight(src_dib) - y) * FreeImage_GetPitch(dst_dib)) + (x * 3);
375 	BYTE *src_bits = FreeImage_GetBits(src_dib);
376 
377 	if(alpha > 255) {
378 		// combine images
379 		for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) {
380 			memcpy(dst_bits, src_bits, FreeImage_GetLine(src_dib));
381 
382 			dst_bits += FreeImage_GetPitch(dst_dib);
383 			src_bits += FreeImage_GetPitch(src_dib);
384 		}
385 	} else {
386 		// alpha blend images
387 		for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) {
388 			for (unsigned cols = 0; cols < FreeImage_GetLine(src_dib); cols++) {
389 				dst_bits[cols] = (BYTE)(((src_bits[cols] - dst_bits[cols]) * alpha + (dst_bits[cols] << 8)) >> 8);
390 			}
391 
392 			dst_bits += FreeImage_GetPitch(dst_dib);
393 			src_bits += FreeImage_GetPitch(src_dib);
394 		}
395 	}
396 
397 	return TRUE;
398 }
399 
400 // ----------------------------------------------------------
401 //   32-bit
402 // ----------------------------------------------------------
403 
404 static BOOL
Combine32(FIBITMAP * dst_dib,FIBITMAP * src_dib,unsigned x,unsigned y,unsigned alpha)405 Combine32(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) {
406 	// check the bit depth of src and dst images
407 	if((FreeImage_GetBPP(dst_dib) != 32) || (FreeImage_GetBPP(src_dib) != 32)) {
408 		return FALSE;
409 	}
410 
411 	// check the size of src image
412 	if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
413 		return FALSE;
414 	}
415 
416 	BYTE *dst_bits = FreeImage_GetBits(dst_dib) + ((FreeImage_GetHeight(dst_dib) - FreeImage_GetHeight(src_dib) - y) * FreeImage_GetPitch(dst_dib)) + (x * 4);
417 	BYTE *src_bits = FreeImage_GetBits(src_dib);
418 
419 	if (alpha > 255) {
420 		// combine images
421 		for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) {
422 			memcpy(dst_bits, src_bits, FreeImage_GetLine(src_dib));
423 
424 			dst_bits += FreeImage_GetPitch(dst_dib);
425 			src_bits += FreeImage_GetPitch(src_dib);
426 		}
427 	} else {
428 		// alpha blend images
429 		for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) {
430 			for(unsigned cols = 0; cols < FreeImage_GetLine(src_dib); cols++) {
431 				dst_bits[cols] = (BYTE)(((src_bits[cols] - dst_bits[cols]) * alpha + (dst_bits[cols] << 8)) >> 8);
432 			}
433 
434 			dst_bits += FreeImage_GetPitch(dst_dib);
435 			src_bits += FreeImage_GetPitch(src_dib);
436 		}
437 	}
438 
439 	return TRUE;
440 }
441 
442 // ----------------------------------------------------------
443 //   Any type other than FIBITMAP
444 // ----------------------------------------------------------
445 
446 static BOOL
CombineSameType(FIBITMAP * dst_dib,FIBITMAP * src_dib,unsigned x,unsigned y)447 CombineSameType(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y) {
448 	// check the bit depth of src and dst images
449 	if(FreeImage_GetImageType(dst_dib) != FreeImage_GetImageType(src_dib)) {
450 		return FALSE;
451 	}
452 
453 	unsigned src_width  = FreeImage_GetWidth(src_dib);
454 	unsigned src_height = FreeImage_GetHeight(src_dib);
455 	unsigned src_pitch  = FreeImage_GetPitch(src_dib);
456 	unsigned src_line   = FreeImage_GetLine(src_dib);
457 	unsigned dst_width  = FreeImage_GetWidth(dst_dib);
458 	unsigned dst_height = FreeImage_GetHeight(dst_dib);
459 	unsigned dst_pitch  = FreeImage_GetPitch(dst_dib);
460 
461 	// check the size of src image
462 	if((x + src_width > dst_width) || (y + src_height > dst_height)) {
463 		return FALSE;
464 	}
465 
466 	BYTE *dst_bits = FreeImage_GetBits(dst_dib) + ((dst_height - src_height - y) * dst_pitch) + (x * (src_line / src_width));
467 	BYTE *src_bits = FreeImage_GetBits(src_dib);
468 
469 	// combine images
470 	for(unsigned rows = 0; rows < src_height; rows++) {
471 		memcpy(dst_bits, src_bits, src_line);
472 
473 		dst_bits += dst_pitch;
474 		src_bits += src_pitch;
475 	}
476 
477 	return TRUE;
478 }
479 
480 // ----------------------------------------------------------
481 //   FreeImage interface
482 // ----------------------------------------------------------
483 
484 /**
485 Copy a sub part of the current image and returns it as a FIBITMAP*.
486 Works with any bitmap type.
487 @param left Specifies the left position of the cropped rectangle.
488 @param top Specifies the top position of the cropped rectangle.
489 @param right Specifies the right position of the cropped rectangle.
490 @param bottom Specifies the bottom position of the cropped rectangle.
491 @return Returns the subimage if successful, NULL otherwise.
492 */
493 FIBITMAP * DLL_CALLCONV
FreeImage_Copy(FIBITMAP * src,int left,int top,int right,int bottom)494 FreeImage_Copy(FIBITMAP *src, int left, int top, int right, int bottom) {
495 
496 	if(!FreeImage_HasPixels(src))
497 		return NULL;
498 
499 	// normalize the rectangle
500 	if(right < left) {
501 		INPLACESWAP(left, right);
502 	}
503 	if(bottom < top) {
504 		INPLACESWAP(top, bottom);
505 	}
506 	// check the size of the sub image
507 	int src_width  = FreeImage_GetWidth(src);
508 	int src_height = FreeImage_GetHeight(src);
509 	if((left < 0) || (right > src_width) || (top < 0) || (bottom > src_height)) {
510 		return NULL;
511 	}
512 
513 	// allocate the sub image
514 	unsigned bpp = FreeImage_GetBPP(src);
515 	int dst_width = (right - left);
516 	int dst_height = (bottom - top);
517 
518 	FIBITMAP *dst =
519 		FreeImage_AllocateT(FreeImage_GetImageType(src),
520 							dst_width,
521 							dst_height,
522 							bpp,
523 							FreeImage_GetRedMask(src), FreeImage_GetGreenMask(src), FreeImage_GetBlueMask(src));
524 
525 	if(NULL == dst) return NULL;
526 
527 	// get the dimensions
528 	int dst_line = FreeImage_GetLine(dst);
529 	int dst_pitch = FreeImage_GetPitch(dst);
530 	int src_pitch = FreeImage_GetPitch(src);
531 
532 	// get the pointers to the bits and such
533 
534 	BYTE *src_bits = FreeImage_GetScanLine(src, src_height - top - dst_height);
535 	switch(bpp) {
536 		case 1:
537 			// point to x = 0
538 			break;
539 
540 		case 4:
541 			// point to x = 0
542 			break;
543 
544 		default:
545 		{
546 			// calculate the number of bytes per pixel
547 			unsigned bytespp = FreeImage_GetLine(src) / FreeImage_GetWidth(src);
548 			// point to x = left
549 			src_bits += left * bytespp;
550 		}
551 		break;
552 	}
553 
554 	// point to x = 0
555 	BYTE *dst_bits = FreeImage_GetBits(dst);
556 
557 	// copy the palette
558 
559 	memcpy(FreeImage_GetPalette(dst), FreeImage_GetPalette(src), FreeImage_GetColorsUsed(src) * sizeof(RGBQUAD));
560 
561 	// copy the bits
562 	if(bpp == 1) {
563 		BOOL value;
564 		unsigned y_src, y_dst;
565 
566 		for(int y = 0; y < dst_height; y++) {
567 			y_src = y * src_pitch;
568 			y_dst = y * dst_pitch;
569 			for(int x = 0; x < dst_width; x++) {
570 				// get bit at (y, x) in src image
571 				value = (src_bits[y_src + ((left+x) >> 3)] & (0x80 >> ((left+x) & 0x07))) != 0;
572 				// set bit at (y, x) in dst image
573 				value ? dst_bits[y_dst + (x >> 3)] |= (0x80 >> (x & 0x7)) : dst_bits[y_dst + (x >> 3)] &= (0xff7f >> (x & 0x7));
574 			}
575 		}
576 	}
577 
578 	else if(bpp == 4) {
579 		BYTE shift, value;
580 		unsigned y_src, y_dst;
581 
582 		for(int y = 0; y < dst_height; y++) {
583 			y_src = y * src_pitch;
584 			y_dst = y * dst_pitch;
585 			for(int x = 0; x < dst_width; x++) {
586 				// get nibble at (y, x) in src image
587 				shift = (BYTE)((1 - (left+x) % 2) << 2);
588 				value = (src_bits[y_src + ((left+x) >> 1)] & (0x0F << shift)) >> shift;
589 				// set nibble at (y, x) in dst image
590 				shift = (BYTE)((1 - x % 2) << 2);
591 				dst_bits[y_dst + (x >> 1)] &= ~(0x0F << shift);
592 				dst_bits[y_dst + (x >> 1)] |= ((value & 0x0F) << shift);
593 			}
594 		}
595 	}
596 
597 	else if(bpp >= 8) {
598 		for(int y = 0; y < dst_height; y++) {
599 			memcpy(dst_bits + (y * dst_pitch), src_bits + (y * src_pitch), dst_line);
600 		}
601 	}
602 
603 	// copy metadata from src to dst
604 	FreeImage_CloneMetadata(dst, src);
605 
606 	// copy transparency table
607 	FreeImage_SetTransparencyTable(dst, FreeImage_GetTransparencyTable(src), FreeImage_GetTransparencyCount(src));
608 
609 	// copy background color
610 	RGBQUAD bkcolor;
611 	if( FreeImage_GetBackgroundColor(src, &bkcolor) ) {
612 		FreeImage_SetBackgroundColor(dst, &bkcolor);
613 	}
614 
615 	// clone resolution
616 	FreeImage_SetDotsPerMeterX(dst, FreeImage_GetDotsPerMeterX(src));
617 	FreeImage_SetDotsPerMeterY(dst, FreeImage_GetDotsPerMeterY(src));
618 
619 	// clone ICC profile
620 	FIICCPROFILE *src_profile = FreeImage_GetICCProfile(src);
621 	FIICCPROFILE *dst_profile = FreeImage_CreateICCProfile(dst, src_profile->data, src_profile->size);
622 	dst_profile->flags = src_profile->flags;
623 
624 	return dst;
625 }
626 
627 /**
628 Alpha blend or combine a sub part image with the current image.
629 The bit depth of dst bitmap must be greater than or equal to the bit depth of src.
630 Upper promotion of src is done internally. Supported bit depth equals to 1, 4, 8, 16, 24 or 32.
631 @param src Source subimage
632 @param left Specifies the left position of the sub image.
633 @param top Specifies the top position of the sub image.
634 @param alpha Alpha blend factor. The source and destination images are alpha blended if
635 alpha = 0..255. If alpha > 255, then the source image is combined to the destination image.
636 @return Returns TRUE if successful, FALSE otherwise.
637 */
638 BOOL DLL_CALLCONV
FreeImage_Paste(FIBITMAP * dst,FIBITMAP * src,int left,int top,int alpha)639 FreeImage_Paste(FIBITMAP *dst, FIBITMAP *src, int left, int top, int alpha) {
640 	BOOL bResult = FALSE;
641 
642 	if(!FreeImage_HasPixels(src) || !FreeImage_HasPixels(dst)) return FALSE;
643 
644 	// check the size of src image
645 	if((left < 0) || (top < 0)) {
646 		return FALSE;
647 	}
648 	if((left + FreeImage_GetWidth(src) > FreeImage_GetWidth(dst)) || (top + FreeImage_GetHeight(src) > FreeImage_GetHeight(dst))) {
649 		return FALSE;
650 	}
651 
652 	// check data type
653 	const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dst);
654 	if(image_type != FreeImage_GetImageType(src)) {
655 		// no conversion between data type is done
656 		return FALSE;
657 	}
658 
659 	if(image_type == FIT_BITMAP) {
660 		FIBITMAP *clone = NULL;
661 
662 		// check the bit depth of src and dst images
663 		unsigned bpp_src = FreeImage_GetBPP(src);
664 		unsigned bpp_dst = FreeImage_GetBPP(dst);
665 		BOOL isRGB565 = FALSE;
666 
667 		if ((FreeImage_GetRedMask(dst) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dst) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dst) == FI16_565_BLUE_MASK)) {
668 			isRGB565 = TRUE;
669 		} else {
670 			// includes case where all the masks are 0
671 			isRGB565 = FALSE;
672 		}
673 
674 		// perform promotion if needed
675 		if(bpp_dst == bpp_src) {
676 			clone = src;
677 		} else if(bpp_dst > bpp_src) {
678 			// perform promotion
679 			switch(bpp_dst) {
680 				case 4:
681 					clone = FreeImage_ConvertTo4Bits(src);
682 					break;
683 				case 8:
684 					clone = FreeImage_ConvertTo8Bits(src);
685 					break;
686 				case 16:
687 					if (isRGB565) {
688 						clone = FreeImage_ConvertTo16Bits565(src);
689 					} else {
690 						// includes case where all the masks are 0
691 						clone = FreeImage_ConvertTo16Bits555(src);
692 					}
693 					break;
694 				case 24:
695 					clone = FreeImage_ConvertTo24Bits(src);
696 					break;
697 				case 32:
698 					clone = FreeImage_ConvertTo32Bits(src);
699 					break;
700 				default:
701 					return FALSE;
702 			}
703 		} else {
704 			return FALSE;
705 		}
706 
707 		if(!clone) return FALSE;
708 
709 		// paste src to dst
710 		switch(FreeImage_GetBPP(dst)) {
711 			case 1:
712 				bResult = Combine1(dst, clone, (unsigned)left, (unsigned)top, (unsigned)alpha);
713 				break;
714 			case 4:
715 				bResult = Combine4(dst, clone, (unsigned)left, (unsigned)top, (unsigned)alpha);
716 				break;
717 			case 8:
718 				bResult = Combine8(dst, clone, (unsigned)left, (unsigned)top, (unsigned)alpha);
719 				break;
720 			case 16:
721 				if (isRGB565) {
722 					bResult = Combine16_565(dst, clone, (unsigned)left, (unsigned)top, (unsigned)alpha);
723 				} else {
724 					// includes case where all the masks are 0
725 					bResult = Combine16_555(dst, clone, (unsigned)left, (unsigned)top, (unsigned)alpha);
726 				}
727 				break;
728 			case 24:
729 				bResult = Combine24(dst, clone, (unsigned)left, (unsigned)top, (unsigned)alpha);
730 				break;
731 			case 32:
732 				bResult = Combine32(dst, clone, (unsigned)left, (unsigned)top, (unsigned)alpha);
733 				break;
734 		}
735 
736 		if(clone != src)
737 			FreeImage_Unload(clone);
738 
739 		}
740 	else {	// any type other than FITBITMAP
741 		bResult = CombineSameType(dst, src, (unsigned)left, (unsigned)top);
742 	}
743 
744 	return bResult;
745 }
746 
747 // ----------------------------------------------------------
748 
749 /** @brief Creates a dynamic read/write view into a FreeImage bitmap.
750 
751  A dynamic view is a FreeImage bitmap with its own width and height, that,
752  however, shares its bits with another FreeImage bitmap. Typically, views
753  are used to define one or more rectangular sub-images of an existing
754  bitmap. All FreeImage operations, like saving, displaying and all the
755  toolkit functions, when applied to the view, only affect the view's
756  rectangular area.
757 
758  Although the view's backing image's bits not need to be copied around,
759  which makes the view much faster than similar solutions using
760  FreeImage_Copy, a view uses some private memory that needs to be freed by
761  calling FreeImage_Unload on the view's handle to prevent memory leaks.
762 
763  Only the backing image's pixels are shared by the view. For all other image
764  data, notably for the resolution, background color, color palette,
765  transparency table and for the ICC profile, the view gets a private copy
766  of the data. By default, the backing image's metadata is NOT copied to
767  the view.
768 
769  As with all FreeImage functions that take a rectangle region, top and left
770  positions are included, whereas right and bottom positions are excluded
771  from the rectangle area.
772 
773  Since the memory block shared by the backing image and the view must start
774  at a byte boundary, the value of parameter left must be a multiple of 8
775  for 1-bit images and a multiple of 2 for 4-bit images.
776 
777  @param dib The FreeImage bitmap on which to create the view.
778  @param left The left position of the view's area.
779  @param top The top position of the view's area.
780  @param right The right position of the view's area.
781  @param bottom The bottom position of the view's area.
782  @return Returns a handle to the newly created view or NULL if the view
783  was not created.
784  */
785 FIBITMAP * DLL_CALLCONV
FreeImage_CreateView(FIBITMAP * dib,unsigned left,unsigned top,unsigned right,unsigned bottom)786 FreeImage_CreateView(FIBITMAP *dib, unsigned left, unsigned top, unsigned right, unsigned bottom) {
787 	if (!FreeImage_HasPixels(dib)) {
788 		return NULL;
789 	}
790 
791 	// normalize the rectangle
792 	if (right < left) {
793 		INPLACESWAP(left, right);
794 	}
795 	if (bottom < top) {
796 		INPLACESWAP(top, bottom);
797 	}
798 
799 	// check the size of the sub image
800 	unsigned width = FreeImage_GetWidth(dib);
801 	unsigned height = FreeImage_GetHeight(dib);
802 	if (left < 0 || right > width || top < 0 || bottom > height) {
803 		return NULL;
804 	}
805 
806 	unsigned bpp = FreeImage_GetBPP(dib);
807 	BYTE *bits = FreeImage_GetScanLine(dib, height - bottom);
808 	switch (bpp) {
809 		case 1:
810 			if (left % 8 != 0) {
811 				// view can only start at a byte boundary
812 				return NULL;
813 			}
814 			bits += (left / 8);
815 			break;
816 		case 4:
817 			if (left % 2 != 0) {
818 				// view can only start at a byte boundary
819 				return NULL;
820 				}
821 			bits += (left / 2);
822 			break;
823 		default:
824 			bits += left * (bpp / 8);
825 			break;
826 	}
827 
828 	FIBITMAP *dst = FreeImage_AllocateHeaderForBits(bits, FreeImage_GetPitch(dib), FreeImage_GetImageType(dib),
829 		right - left, bottom - top,
830 		bpp,
831 		FreeImage_GetRedMask(dib), FreeImage_GetGreenMask(dib), FreeImage_GetBlueMask(dib));
832 
833 	if (dst == NULL) {
834 		return NULL;
835 	}
836 
837 	// copy some basic image properties needed for displaying and saving
838 
839 	// resolution
840 	FreeImage_SetDotsPerMeterX(dst, FreeImage_GetDotsPerMeterX(dib));
841 	FreeImage_SetDotsPerMeterY(dst, FreeImage_GetDotsPerMeterY(dib));
842 
843 	// background color
844 	RGBQUAD bkcolor;
845 	if (FreeImage_GetBackgroundColor(dib, &bkcolor)) {
846 		FreeImage_SetBackgroundColor(dst, &bkcolor);
847 	}
848 
849 	// palette
850 	memcpy(FreeImage_GetPalette(dst), FreeImage_GetPalette(dib), FreeImage_GetColorsUsed(dib) * sizeof(RGBQUAD));
851 
852 	// transparency table
853 	FreeImage_SetTransparencyTable(dst, FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib));
854 
855 	// ICC profile
856 	FIICCPROFILE *src_profile = FreeImage_GetICCProfile(dib);
857 	FIICCPROFILE *dst_profile = FreeImage_CreateICCProfile(dst, src_profile->data, src_profile->size);
858 	dst_profile->flags = src_profile->flags;
859 
860 	return dst;
861 }
862