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