PageRenderTime 73ms CodeModel.GetById 14ms app.highlight 53ms RepoModel.GetById 1ms app.codeStats 0ms

/src/FreeImage/Source/FreeImageToolkit/CopyPaste.cpp

https://bitbucket.org/cabalistic/ogredeps/
C++ | 747 lines | 455 code | 142 blank | 150 comment | 148 complexity | d1cd20fd1e97339cc0e85d5f8ce2d3d6 MD5 | raw file
  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//
 10// This file is part of FreeImage 3
 11//
 12// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
 13// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
 14// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
 15// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
 16// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
 17// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
 18// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
 19// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
 20// THIS DISCLAIMER.
 21//
 22// Use at your own risk!
 23// ==========================================================
 24
 25#include "FreeImage.h"
 26#include "Utilities.h"
 27
 28// ----------------------------------------------------------
 29//   Helpers
 30// ----------------------------------------------------------
 31
 32/////////////////////////////////////////////////////////////
 33// Alpha blending / combine functions
 34
 35// ----------------------------------------------------------
 36/// 1-bit
 37static BOOL Combine1(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha);
 38/// 4-bit
 39static BOOL Combine4(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha);
 40/// 8-bit
 41static BOOL Combine8(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha);
 42/// 16-bit 555
 43static BOOL Combine16_555(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha);
 44/// 16-bit 565
 45static BOOL Combine16_565(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha);
 46/// 24-bit
 47static BOOL Combine24(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha);
 48/// 32- bit
 49static BOOL Combine32(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha);
 50// ----------------------------------------------------------
 51
 52// ----------------------------------------------------------
 53//   1-bit
 54// ----------------------------------------------------------
 55
 56static BOOL 
 57Combine1(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) {
 58	BOOL value;
 59
 60	// check the bit depth of src and dst images
 61	if((FreeImage_GetBPP(dst_dib) != 1) || (FreeImage_GetBPP(src_dib) != 1)) {
 62		return FALSE;
 63	}
 64
 65	// check the size of src image
 66	if((x + FreeImage_GetWidth(src_dib) > FreeImage_GetWidth(dst_dib)) || (y + FreeImage_GetHeight(src_dib) > FreeImage_GetHeight(dst_dib))) {
 67		return FALSE;
 68	}
 69
 70	BYTE *dst_bits = FreeImage_GetBits(dst_dib) + ((FreeImage_GetHeight(dst_dib) - FreeImage_GetHeight(src_dib) - y) * FreeImage_GetPitch(dst_dib));
 71	BYTE *src_bits = FreeImage_GetBits(src_dib);	
 72
 73	// combine images
 74	for(unsigned rows = 0; rows < FreeImage_GetHeight(src_dib); rows++) {
 75		for(unsigned cols = 0; cols < FreeImage_GetWidth(src_dib); cols++) {
 76			// get bit at (rows, cols) in src image
 77			value = (src_bits[cols >> 3] & (0x80 >> (cols & 0x07))) != 0;
 78			// set bit at (rows, x+cols) in dst image	
 79			value ? dst_bits[(x + cols) >> 3] |= (0x80 >> ((x + cols) & 0x7)) : dst_bits[(x + cols) >> 3] &= (0xFF7F >> ((x + cols) & 0x7));
 80		}
 81
 82		dst_bits += FreeImage_GetPitch(dst_dib);
 83		src_bits += FreeImage_GetPitch(src_dib);
 84	}
 85
 86	return TRUE;
 87}
 88
 89// ----------------------------------------------------------
 90//   4-bit
 91// ----------------------------------------------------------
 92
 93static BOOL 
 94Combine4(FIBITMAP *dst_dib, FIBITMAP *src_dib, unsigned x, unsigned y, unsigned alpha) {
 95
 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
196static BOOL 
197Combine8(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
238static BOOL 
239Combine16_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
298static BOOL 
299Combine16_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
362static BOOL 
363Combine24(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
404static BOOL 
405Combine32(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
446static BOOL 
447CombineSameType(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/**
485Copy a sub part of the current image and returns it as a FIBITMAP*.
486Works 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*/
493FIBITMAP * DLL_CALLCONV 
494FreeImage_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/**
628Alpha blend or combine a sub part image with the current image.
629The bit depth of dst bitmap must be greater than or equal to the bit depth of src. 
630Upper 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 
635alpha = 0..255. If alpha > 255, then the source image is combined to the destination image.
636@return Returns TRUE if successful, FALSE otherwise.
637*/
638BOOL DLL_CALLCONV 
639FreeImage_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