1 // ==========================================================
2 // Background filling routines
3 //
4 // Design and implementation by
5 // - Carsten Klein (c.klein@datagis.com)
6 //
7 // This file is part of FreeImage 3
8 //
9 // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
10 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
11 // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
12 // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
13 // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
14 // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
15 // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
16 // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
17 // THIS DISCLAIMER.
18 //
19 // Use at your own risk!
20 // ==========================================================
21 
22 #include "FreeImage.h"
23 #include "Utilities.h"
24 
25 /** @brief Determines, whether a palletized image is visually greyscale or not.
26 
27  Unlike with FreeImage_GetColorType, which returns either FIC_MINISBLACK or
28  FIC_MINISWHITE for a greyscale image with a linear ramp palette, the return
29  value of this function does not depend on the palette's order, but only on the
30  palette's individual colors.
31  @param dib The image to be tested.
32  @return Returns TRUE if the palette of the image specified contains only
33  greyscales, FALSE otherwise.
34  */
35 static BOOL
IsVisualGreyscaleImage(FIBITMAP * dib)36 IsVisualGreyscaleImage(FIBITMAP *dib) {
37 
38 	switch (FreeImage_GetBPP(dib)) {
39 		case 1:
40 		case 4:
41 		case 8: {
42 			unsigned ncolors = FreeImage_GetColorsUsed(dib);
43 			RGBQUAD *rgb = FreeImage_GetPalette(dib);
44 			for (unsigned i = 0; i< ncolors; i++) {
45 				if ((rgb->rgbRed != rgb->rgbGreen) || (rgb->rgbRed != rgb->rgbBlue)) {
46 					return FALSE;
47 				}
48 			}
49 			return TRUE;
50 		}
51 		default: {
52 			return (FreeImage_GetColorType(dib) == FIC_MINISBLACK);
53 		}
54 	}
55 }
56 
57 /** @brief Looks up a specified color in a FIBITMAP's palette and returns the color's
58  palette index or -1 if the color was not found.
59 
60  Unlike with FreeImage_GetColorType, which returns either FIC_MINISBLACK or
61  FIC_MINISWHITE for a greyscale image with a linear ramp palette, the return
62  value of this function does not depend on the palette's order, but only on the
63  palette's individual colors.
64  @param dib The image, whose palette should be searched through.
65  @param color The color to be searched in the palette.
66  @param options Options that affect the color search process.
67  @param color_type A pointer, that optionally specifies the image's color type as
68  returned by FreeImage_GetColorType. If invalid or NULL, this function determines the
69  color type with FreeImage_GetColorType.
70  @return Returns the specified color's palette index, the color's rgbReserved member
71  if option FI_COLOR_ALPHA_IS_INDEX was specified or -1, if the color was not found
72  in the image's palette or if the specified image is non-palletized.
73  */
74 static int
GetPaletteIndex(FIBITMAP * dib,const RGBQUAD * color,int options,FREE_IMAGE_COLOR_TYPE * color_type)75 GetPaletteIndex(FIBITMAP *dib, const RGBQUAD *color, int options, FREE_IMAGE_COLOR_TYPE *color_type) {
76 
77 	int result = -1;
78 
79 	if ((!dib) || (!color)) {
80 		return result;
81 	}
82 
83 	int bpp = FreeImage_GetBPP(dib);
84 
85 	// First check trivial case: return color->rgbReserved if only
86 	// FI_COLOR_ALPHA_IS_INDEX is set.
87 	if ((options & FI_COLOR_ALPHA_IS_INDEX) == FI_COLOR_ALPHA_IS_INDEX) {
88 		if (bpp == 1) {
89 			return color->rgbReserved & 0x01;
90 		} else if (bpp == 4) {
91 			return color->rgbReserved & 0x0F;
92 		}
93 		return color->rgbReserved;
94 	}
95 
96 	if (bpp == 8) {
97 		FREE_IMAGE_COLOR_TYPE ct =
98 			(color_type == NULL || *color_type < 0) ?
99 				FreeImage_GetColorType(dib) : *color_type;
100 		if (ct == FIC_MINISBLACK) {
101 			return GREY(color->rgbRed, color->rgbGreen, color->rgbBlue);
102 		}
103 		if (ct == FIC_MINISWHITE) {
104 			return 255 - GREY(color->rgbRed, color->rgbGreen, color->rgbBlue);
105 		}
106 	} else if (bpp > 8) {
107 		// for palettized images only
108 		return result;
109 	}
110 
111 	if (options & FI_COLOR_FIND_EQUAL_COLOR) {
112 
113 		// Option FI_COLOR_ALPHA_IS_INDEX is implicit here so, set
114 		// index to color->rgbReserved
115 		result = color->rgbReserved;
116 		if (bpp == 1) {
117 			result &= 0x01;
118 		} else if (bpp == 4) {
119 			result &= 0x0F;
120 		}
121 
122 		unsigned ucolor;
123 		if (!IsVisualGreyscaleImage(dib)) {
124 			ucolor = (*((unsigned *)color)) & 0xFFFFFF;
125 		} else {
126 			ucolor = GREY(color->rgbRed, color->rgbGreen, color->rgbBlue) * 0x010101;
127 			//ucolor = (ucolor | (ucolor << 8) | (ucolor << 16));
128 		}
129 		unsigned ncolors = FreeImage_GetColorsUsed(dib);
130 		unsigned *palette = (unsigned *)FreeImage_GetPalette(dib);
131 		for (unsigned i = 0; i < ncolors; i++) {
132 			if ((palette[i] & 0xFFFFFF) == ucolor) {
133 				result = i;
134 				break;
135 			}
136 		}
137 	} else {
138 		unsigned minimum = UINT_MAX;
139 		unsigned ncolors = FreeImage_GetColorsUsed(dib);
140 		BYTE *palette = (BYTE *)FreeImage_GetPalette(dib);
141 		BYTE red, green, blue;
142 		if (!IsVisualGreyscaleImage(dib)) {
143 			red = color->rgbRed;
144 			green = color->rgbGreen;
145 			blue = color->rgbBlue;
146 		} else {
147 			red = GREY(color->rgbRed, color->rgbGreen, color->rgbBlue);
148 			green = blue = red;
149 		}
150 		for (unsigned i = 0; i < ncolors; i++) {
151 			unsigned m = abs(palette[FI_RGBA_BLUE] - blue)
152 					+ abs(palette[FI_RGBA_GREEN] - green)
153 					+ abs(palette[FI_RGBA_RED] - red);
154 			if (m < minimum) {
155 				minimum = m;
156 				result = i;
157 				if (m == 0) {
158 					break;
159 				}
160 			}
161 			palette += sizeof(RGBQUAD);
162 		}
163 	}
164 	return result;
165 }
166 
167 /** @brief Blends an alpha-transparent foreground color over an opaque background
168  color.
169 
170  This function blends the alpha-transparent foreground color fgcolor over the
171  background color bgcolor. The background color is considered fully opaque,
172  whatever it's alpha value contains, whereas the foreground color is considered
173  to be a real RGBA color with an alpha value, which is used for the blend
174  operation. The resulting color is returned through the blended parameter.
175  @param bgcolor The background color for the blend operation.
176  @param fgcolor The foreground color for the blend operation. This color's alpha
177  value, stored in the rgbReserved member, is the alpha value used for the blend
178  operation.
179  @param blended This out parameter takes the blended color and so, returns it to
180  the caller. This color's alpha value will be 0xFF (255) so, the blended color
181  itself has no transparency. The this argument is not changed, if the function
182  fails.
183  @return Returns TRUE on success, FALSE otherwise. This function fails if any of
184  the color arguments is a null pointer.
185  */
186 static BOOL
GetAlphaBlendedColor(const RGBQUAD * bgcolor,const RGBQUAD * fgcolor,RGBQUAD * blended)187 GetAlphaBlendedColor(const RGBQUAD *bgcolor, const RGBQUAD *fgcolor, RGBQUAD *blended) {
188 
189 	if ((!bgcolor) || (!fgcolor) || (!blended)) {
190 		return FALSE;
191 	}
192 
193 	BYTE alpha = fgcolor->rgbReserved;
194 	BYTE not_alpha = ~alpha;
195 
196 	blended->rgbRed = (BYTE)( ((WORD)fgcolor->rgbRed * alpha + not_alpha * (WORD)bgcolor->rgbRed)   >> 8 );
197 	blended->rgbGreen = (BYTE)( ((WORD)fgcolor->rgbGreen * alpha + not_alpha * (WORD)bgcolor->rgbGreen) >> 8) ;
198 	blended->rgbBlue = (BYTE)(((WORD)fgcolor->rgbBlue * alpha + not_alpha * (WORD)bgcolor->rgbBlue) >> 8);
199 	blended->rgbReserved = 0xFF;
200 
201 	return TRUE;
202 }
203 
204 /** @brief Fills a FIT_BITMAP image with the specified color.
205 
206  This function does the dirty work for FreeImage_FillBackground for FIT_BITMAP
207  images.
208  @param dib The image to be filled.
209  @param color The color, the specified image should be filled with.
210  @param options Options that affect the color search process for palletized images.
211  @return Returns TRUE on success, FALSE otherwise. This function fails if any of
212  the dib and color is NULL or the provided image is not a FIT_BITMAP image.
213  */
214 static BOOL
FillBackgroundBitmap(FIBITMAP * dib,const RGBQUAD * color,int options)215 FillBackgroundBitmap(FIBITMAP *dib, const RGBQUAD *color, int options) {
216 
217 	if ((!dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP)) {
218 		return FALSE;;
219 	}
220 
221 	if (!color) {
222 		return FALSE;
223 	}
224 
225 	const RGBQUAD *color_intl = color;
226 	unsigned bpp = FreeImage_GetBPP(dib);
227 	unsigned width = FreeImage_GetWidth(dib);
228 	unsigned height = FreeImage_GetHeight(dib);
229 
230 	FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib);
231 
232 	// get a pointer to the first scanline (bottom line)
233 	BYTE *src_bits = FreeImage_GetScanLine(dib, 0);
234 	BYTE *dst_bits = src_bits;
235 
236 	BOOL supports_alpha = ((bpp >= 24) || ((bpp == 8) && (color_type != FIC_PALETTE)));
237 
238 	// Check for RGBA case if bitmap supports alpha
239 	// blending (8-bit greyscale, 24- or 32-bit images)
240 	if (supports_alpha && (options & FI_COLOR_IS_RGBA_COLOR)) {
241 
242 		if (color->rgbReserved == 0) {
243 			// the fill color is fully transparent; we are done
244 			return TRUE;
245 		}
246 
247 		// Only if the fill color is NOT fully opaque, draw it with
248 		// the (much) slower FreeImage_DrawLine function and return.
249 		// Since we do not have the FreeImage_DrawLine function in this
250 		// release, just assume to have an unicolor background and fill
251 		// all with an 'alpha-blended' color.
252 		if (color->rgbReserved < 255) {
253 
254 			// If we will draw on an unicolor background, it's
255 			// faster to draw opaque with an alpha blended color.
256 			// So, first get the color from the first pixel in the
257 			// image (bottom-left pixel).
258 			RGBQUAD bgcolor;
259 			if (bpp == 8) {
260 				bgcolor = FreeImage_GetPalette(dib)[*src_bits];
261 			} else {
262 				bgcolor.rgbBlue = src_bits[FI_RGBA_BLUE];
263 				bgcolor.rgbGreen = src_bits[FI_RGBA_GREEN];
264 				bgcolor.rgbRed = src_bits[FI_RGBA_RED];
265 				bgcolor.rgbReserved = 0xFF;
266 			}
267 			RGBQUAD blend;
268 			GetAlphaBlendedColor(&bgcolor, color_intl, &blend);
269 			color_intl = &blend;
270 		}
271 	}
272 
273 	int index = (bpp <= 8) ? GetPaletteIndex(dib, color_intl, options, &color_type) : 0;
274 	if (index == -1) {
275 		// No palette index found for a palletized
276 		// image. This should never happen...
277 		return FALSE;
278 	}
279 
280 	// first, build the first scanline (line 0)
281 	switch (bpp) {
282 		case 1: {
283 			unsigned bytes = (width / 8);
284 			memset(dst_bits, ((index == 1) ? 0xFF : 0x00), bytes);
285 			//int n = width % 8;
286 			int n = width & 7;
287 			if (n) {
288 				if (index == 1) {
289 					// set n leftmost bits
290 					dst_bits[bytes] |= (0xFF << (8 - n));
291 				} else {
292 					// clear n leftmost bits
293 					dst_bits[bytes] &= (0xFF >> n);
294 				}
295 			}
296 			break;
297 		}
298 		case 4: {
299 			unsigned bytes = (width / 2);
300 			memset(dst_bits, (index | (index << 4)), bytes);
301 			//if (bytes % 2) {
302 			if (bytes & 1) {
303 				dst_bits[bytes] &= 0x0F;
304 				dst_bits[bytes] |= (index << 4);
305 			}
306 			break;
307 		}
308 		case 8: {
309 			memset(dst_bits, index, FreeImage_GetLine(dib));
310 			break;
311 		}
312 		case 16: {
313 			WORD wcolor = RGBQUAD_TO_WORD(dib, color_intl);
314 			for (unsigned x = 0; x < width; x++) {
315 				((WORD *)dst_bits)[x] = wcolor;
316 			}
317 			break;
318 		}
319 		case 24: {
320 			RGBTRIPLE rgbt = *((RGBTRIPLE *)color_intl);
321 			for (unsigned x = 0; x < width; x++) {
322 				((RGBTRIPLE *)dst_bits)[x] = rgbt;
323 			}
324 			break;
325 		}
326 		case 32: {
327 			RGBQUAD rgbq;
328 			rgbq.rgbBlue = ((RGBTRIPLE *)color_intl)->rgbtBlue;
329 			rgbq.rgbGreen = ((RGBTRIPLE *)color_intl)->rgbtGreen;
330 			rgbq.rgbRed = ((RGBTRIPLE *)color_intl)->rgbtRed;
331 			rgbq.rgbReserved = 0xFF;
332 			for (unsigned x = 0; x < width; x++) {
333 				((RGBQUAD *)dst_bits)[x] = rgbq;
334 			}
335 			break;
336 		}
337 		default:
338 			return FALSE;
339 	}
340 
341 	// Then, copy the first scanline into all following scanlines.
342 	// 'src_bits' is a pointer to the first scanline and is already
343 	// set up correctly.
344 	if (src_bits) {
345 		unsigned pitch = FreeImage_GetPitch(dib);
346 		unsigned bytes = FreeImage_GetLine(dib);
347 		dst_bits = src_bits + pitch;
348 		for (unsigned y = 1; y < height; y++) {
349 			memcpy(dst_bits, src_bits, bytes);
350 			dst_bits += pitch;
351 		}
352 	}
353 	return TRUE;
354 }
355 
356 /** @brief Fills an image with the specified color.
357 
358  This function sets all pixels of an image to the color provided through the color
359  parameter. Since this should work for all image types supported by FreeImage, the
360  pointer color must point to a memory location, which is at least as large as the
361  image's color value, if this size is greater than 4 bytes. As the color is specified
362  by an RGBQUAD structure for all images of type FIT_BITMAP (including all palletized
363  images), the smallest possible size of this memory is the size of the RGBQUAD structure,
364  which uses 4 bytes.
365 
366  So, color must point to a double, if the image to be filled is of type FIT_DOUBLE and
367  point to a RGBF structure if the image is of type FIT_RGBF and so on.
368 
369  However, the fill color is always specified through a RGBQUAD structure for all images
370  of type FIT_BITMAP. So, for 32- and 24-bit images, the red, green and blue members of
371  the RGBQUAD structure are directly used for the image's red, green and blue channel
372  respectively. Although alpha transparent RGBQUAD colors are supported, the alpha channel
373  of a 32-bit image never gets modified by this function. A fill color with an alpha value
374  smaller than 255 gets blended with the image's actual background color, which is determined
375  from the image's bottom-left pixel. So, currently using alpha enabled colors, assumes the
376  image to be unicolor before the fill operation. However, the RGBQUAD's rgbReserved member is
377  only taken into account, if option FI_COLOR_IS_RGBA_COLOR has been specified.
378 
379  For 16-bit images, the red-, green- and blue components of the specified color are
380  transparently translated into either the 16-bit 555 or 565 representation. This depends
381  on the image's actual red- green- and blue masks.
382 
383  Special attention must be payed for palletized images. Generally, the RGB color specified
384  is looked up in the image's palette. The found palette index is then used to fill the image.
385  There are some option flags, that affect this lookup process:
386 
387  no option specified       (0x00)   Uses the color, that is nearest to the specified color.
388                                     This is the default behavior and should always find a
389                                     color in the palette. However, the visual result may
390                                     far from what was expected and mainly depends on the
391                                     image's palette.
392 
393  FI_COLOR_FIND_EQUAL_COLOR (0x02)	Searches the image's palette for the specified color
394                                     but only uses the returned palette index, if the specified
395                                     color exactly matches the palette entry. Of course,
396                                     depending on the image's actual palette entries, this
397                                     operation may fail. In this case, the function falls back
398                                     to option FI_COLOR_ALPHA_IS_INDEX and uses the RGBQUAD's
399                                     rgbReserved member (or its low nibble for 4-bit images
400                                     or its least significant bit (LSB) for 1-bit images) as
401                                     the palette index used for the fill operation.
402 
403  FI_COLOR_ALPHA_IS_INDEX   (0x04)   Does not perform any color lookup from the palette, but
404                                     uses the RGBQUAD's alpha channel member rgbReserved as
405                                     the palette index to be used for the fill operation.
406                                     However, for 4-bit images, only the low nibble of the
407                                     rgbReserved member are used and for 1-bit images, only
408                                     the least significant bit (LSB) is used.
409 
410  This function fails if any of dib and color is NULL.
411 
412  @param dib The image to be filled.
413  @param color A pointer to the color value to be used for filling the image. The
414  memory pointed to by this pointer is always assumed to be at least as large as the
415  image's color value, but never smaller than the size of an RGBQUAD structure.
416  @param options Options that affect the color search process for palletized images.
417  @return Returns TRUE on success, FALSE otherwise. This function fails if any of
418  dib and color is NULL.
419  */
420 BOOL DLL_CALLCONV
FreeImage_FillBackground(FIBITMAP * dib,const void * color,int options)421 FreeImage_FillBackground(FIBITMAP *dib, const void *color, int options) {
422 
423 	if (!FreeImage_HasPixels(dib)) {
424 		return FALSE;
425 	}
426 
427 	if (!color) {
428 		return FALSE;
429 	}
430 
431 	// handle FIT_BITMAP images with FreeImage_FillBackground()
432 	if (FreeImage_GetImageType(dib) == FIT_BITMAP) {
433 		return FillBackgroundBitmap(dib, (RGBQUAD *)color, options);
434 	}
435 
436 	// first, construct the first scanline (bottom line)
437 	unsigned bytespp = (FreeImage_GetBPP(dib) / 8);
438 	BYTE *src_bits = FreeImage_GetScanLine(dib, 0);
439 	BYTE *dst_bits = src_bits;
440 	for (unsigned x = 0; x < FreeImage_GetWidth(dib); x++) {
441 		memcpy(dst_bits, color, bytespp);
442 		dst_bits += bytespp;
443 	}
444 
445 	// then, copy the first scanline into all following scanlines
446 	unsigned height = FreeImage_GetHeight(dib);
447 	unsigned pitch = FreeImage_GetPitch(dib);
448 	unsigned bytes = FreeImage_GetLine(dib);
449 	dst_bits = src_bits + pitch;
450 	for (unsigned y = 1; y < height; y++) {
451 		memcpy(dst_bits, src_bits, bytes);
452 		dst_bits += pitch;
453 	}
454 	return TRUE;
455 }
456 
457 /** @brief Allocates a new image of the specified type, width, height and bit depth and
458  optionally fills it with the specified color.
459 
460  This function is an extension to FreeImage_AllocateT, which additionally supports specifying
461  a palette to be set for the newly create image, as well as specifying a background color,
462  the newly created image should initially be filled with.
463 
464  Basically, this function internally relies on function FreeImage_AllocateT, followed by a
465  call to FreeImage_FillBackground. This is why both parameters color and options behave the
466  same as it is documented for function FreeImage_FillBackground. So, please refer to the
467  documentation of FreeImage_FillBackground to learn more about parameters color and options.
468 
469  The palette specified through parameter palette is only copied to the newly created
470  image, if its image type is FIT_BITMAP and the desired bit depth is smaller than or equal
471  to 8 bits per pixel. In other words, the palette parameter is only taken into account for
472  palletized images. However, if the preceding conditions match and if palette is not NULL,
473  the memory pointed to by the palette pointer is assumed to be at least as large as size
474  of a fully populated palette for the desired bit depth. So, for an 8-bit image, this size
475  is 256 x sizeof(RGBQUAD), for an 4-bit image it is 16 x sizeof(RGBQUAD) and it is
476  2 x sizeof(RGBQUAD) for a 1-bit image. In other words, this function does not support
477  partial palettes.
478 
479  However, specifying a palette is not necessarily needed, even for palletized images. This
480  function is capable of implicitly creating a palette, if parameter palette is NULL. If the
481  specified background color is a greyscale value (red = green = blue) or if option
482  FI_COLOR_ALPHA_IS_INDEX is specified, a greyscale palette is created. For a 1-bit image, only
483  if the specified background color is either black or white, a monochrome palette, consisting
484  of black and white only is created. In any case, the darker colors are stored at the smaller
485  palette indices.
486 
487  If the specified background color is not a greyscale value, or is neither black nor white
488  for a 1-bit image, solely this single color is injected into the otherwise black-initialized
489  palette. For this operation, option FI_COLOR_ALPHA_IS_INDEX is implicit, so the specified
490  color is applied to the palette entry, specified by the background color's rgbReserved
491  member. The image is then filled with this palette index.
492 
493  This function returns a newly created image as function FreeImage_AllocateT does, if both
494  parameters color and palette are NULL. If only color is NULL, the palette pointed to by
495  parameter palette is initially set for the new image, if a palletized image of type
496  FIT_BITMAP is created. However, in the latter case, this function returns an image, whose
497  pixels are all initialized with zeros so, the image will be filled with the color of the
498  first palette entry.
499 
500  @param type Specifies the image type of the new image.
501  @param width The desired width in pixels of the new image.
502  @param height The desired height in pixels of the new image.
503  @param bpp The desired bit depth of the new image.
504  @param color A pointer to the color value to be used for filling the image. The
505  memory pointed to by this pointer is always assumed to be at least as large as the
506  image's color value but never smaller than the size of an RGBQUAD structure.
507  @param options Options that affect the color search process for palletized images.
508  @param red_mask Specifies the bits used to store the red components of a pixel.
509  @param green_mask Specifies the bits used to store the green components of a pixel.
510  @param blue_mask Specifies the bits used to store the blue components of a pixel.
511  @return Returns a pointer to a newly allocated image on success, NULL otherwise.
512  */
513 FIBITMAP * DLL_CALLCONV
FreeImage_AllocateExT(FREE_IMAGE_TYPE type,int width,int height,int bpp,const void * color,int options,const RGBQUAD * palette,unsigned red_mask,unsigned green_mask,unsigned blue_mask)514 FreeImage_AllocateExT(FREE_IMAGE_TYPE type, int width, int height, int bpp, const void *color, int options, const RGBQUAD *palette, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
515 
516 	FIBITMAP *bitmap = FreeImage_AllocateT(type, width, height, bpp, red_mask, green_mask, blue_mask);
517 
518 	if (!color) {
519 		if ((palette) && (type == FIT_BITMAP) && (bpp <= 8)) {
520 			memcpy(FreeImage_GetPalette(bitmap), palette, FreeImage_GetColorsUsed(bitmap) * sizeof(RGBQUAD));
521 		}
522 		return bitmap;
523 	}
524 
525 	if (bitmap != NULL) {
526 
527 		// Only fill the new bitmap if the specified color
528 		// differs from "black", that is not all bytes of the
529 		// color are equal to zero.
530 		switch (bpp) {
531 			case 1: {
532 				// although 1-bit implies FIT_BITMAP, better get an unsigned
533 				// color and palette
534 				unsigned *urgb = (unsigned *)color;
535 				unsigned *upal = (unsigned *)FreeImage_GetPalette(bitmap);
536 				RGBQUAD rgbq = RGBQUAD();
537 
538 				if (palette != NULL) {
539 					// clone the specified palette
540 					memcpy(FreeImage_GetPalette(bitmap), palette, 2 * sizeof(RGBQUAD));
541 				} else if (options & FI_COLOR_ALPHA_IS_INDEX) {
542 					CREATE_GREYSCALE_PALETTE(upal, 2);
543 				} else {
544 					// check, whether the specified color is either black or white
545 					if ((*urgb & 0xFFFFFF) == 0x000000) {
546 						// in any case build a FIC_MINISBLACK palette
547 						CREATE_GREYSCALE_PALETTE(upal, 2);
548 						color = &rgbq;
549 					} else if ((*urgb & 0xFFFFFF) == 0xFFFFFF) {
550 						// in any case build a FIC_MINISBLACK palette
551 						CREATE_GREYSCALE_PALETTE(upal, 2);
552 						rgbq.rgbReserved = 1;
553 						color = &rgbq;
554 					} else {
555 						// Otherwise inject the specified color into the so far
556 						// black-only palette. We use color->rgbReserved as the
557 						// desired palette index.
558 						BYTE index = ((RGBQUAD *)color)->rgbReserved & 0x01;
559 						upal[index] = *urgb & 0x00FFFFFF;
560 					}
561 					options |= FI_COLOR_ALPHA_IS_INDEX;
562 				}
563 				// and defer to FreeImage_FillBackground
564 				FreeImage_FillBackground(bitmap, color, options);
565 				break;
566 			}
567 			case 4: {
568 				// 4-bit implies FIT_BITMAP so, get a RGBQUAD color
569 				RGBQUAD *rgb = (RGBQUAD *)color;
570 				RGBQUAD *pal = FreeImage_GetPalette(bitmap);
571 				RGBQUAD rgbq = RGBQUAD();
572 
573 				if (palette != NULL) {
574 					// clone the specified palette
575 					memcpy(pal, palette, 16 * sizeof(RGBQUAD));
576 				} else if (options & FI_COLOR_ALPHA_IS_INDEX) {
577 					CREATE_GREYSCALE_PALETTE(pal, 16);
578 				} else {
579 					// check, whether the specified color is a grey one
580 					if ((rgb->rgbRed == rgb->rgbGreen) && (rgb->rgbRed == rgb->rgbBlue)) {
581 						// if so, build a greyscale palette
582 						CREATE_GREYSCALE_PALETTE(pal, 16);
583 						rgbq.rgbReserved = rgb->rgbRed >> 4;
584 						color = &rgbq;
585 					} else {
586 						// Otherwise inject the specified color into the so far
587 						// black-only palette. We use color->rgbReserved as the
588 						// desired palette index.
589 						BYTE index = (rgb->rgbReserved & 0x0F);
590 						((unsigned *)pal)[index] = *((unsigned *)rgb) & 0x00FFFFFF;
591 					}
592 					options |= FI_COLOR_ALPHA_IS_INDEX;
593 				}
594 				// and defer to FreeImage_FillBackground
595 				FreeImage_FillBackground(bitmap, color, options);
596 				break;
597 			}
598 			case 8: {
599 				// 8-bit implies FIT_BITMAP so, get a RGBQUAD color
600 				RGBQUAD *rgb = (RGBQUAD *)color;
601 				RGBQUAD *pal = FreeImage_GetPalette(bitmap);
602 				RGBQUAD rgbq;
603 
604 				if (palette != NULL) {
605 					// clone the specified palette
606 					memcpy(pal, palette, 256 * sizeof(RGBQUAD));
607 				} else if (options & FI_COLOR_ALPHA_IS_INDEX) {
608 					CREATE_GREYSCALE_PALETTE(pal, 256);
609 				} else {
610 					// check, whether the specified color is a grey one
611 					if ((rgb->rgbRed == rgb->rgbGreen) && (rgb->rgbRed == rgb->rgbBlue)) {
612 						// if so, build a greyscale palette
613 						CREATE_GREYSCALE_PALETTE(pal, 256);
614 						rgbq.rgbReserved = rgb->rgbRed;
615 						color = &rgbq;
616 					} else {
617 						// Otherwise inject the specified color into the so far
618 						// black-only palette. We use color->rgbReserved as the
619 						// desired palette index.
620 						BYTE index = rgb->rgbReserved;
621 						((unsigned *)pal)[index] = *((unsigned *)rgb) & 0x00FFFFFF;
622 					}
623 					options |= FI_COLOR_ALPHA_IS_INDEX;
624 				}
625 				// and defer to FreeImage_FillBackground
626 				FreeImage_FillBackground(bitmap, color, options);
627 				break;
628 			}
629 			case 16: {
630 				WORD wcolor = (type == FIT_BITMAP) ?
631 					RGBQUAD_TO_WORD(bitmap, ((RGBQUAD *)color)) : *((WORD *)color);
632 				if (wcolor != 0) {
633 					FreeImage_FillBackground(bitmap, color, options);
634 				}
635 				break;
636 			}
637 			default: {
638 				int bytespp = bpp / 8;
639 				for (int i = 0; i < bytespp; i++) {
640 					if (((BYTE *)color)[i] != 0) {
641 						FreeImage_FillBackground(bitmap, color, options);
642 						break;
643 					}
644 				}
645 				break;
646 			}
647 		}
648 	}
649 	return bitmap;
650 }
651 
652 /** @brief Allocates a new image of the specified width, height and bit depth and optionally
653  fills it with the specified color.
654 
655  This function is an extension to FreeImage_Allocate, which additionally supports specifying
656  a palette to be set for the newly create image, as well as specifying a background color,
657  the newly created image should initially be filled with.
658 
659  Basically, this function internally relies on function FreeImage_Allocate, followed by a
660  call to FreeImage_FillBackground. This is why both parameters color and options behave the
661  same as it is documented for function FreeImage_FillBackground. So, please refer to the
662  documentation of FreeImage_FillBackground to learn more about parameters color and options.
663 
664  The palette specified through parameter palette is only copied to the newly created
665  image, if the desired bit depth is smaller than or equal to 8 bits per pixel. In other words,
666  the palette parameter is only taken into account for palletized images. However, if the
667  image to be created is a palletized image and if palette is not NULL, the memory pointed to
668  by the palette pointer is assumed to be at least as large as size of a fully populated
669  palette for the desired bit depth. So, for an 8-bit image, this size is 256 x sizeof(RGBQUAD),
670  for an 4-bit image it is 16 x sizeof(RGBQUAD) and it is 2 x sizeof(RGBQUAD) for a 1-bit
671  image. In other words, this function does not support partial palettes.
672 
673  However, specifying a palette is not necessarily needed, even for palletized images. This
674  function is capable of implicitly creating a palette, if parameter palette is NULL. If the
675  specified background color is a greyscale value (red = green = blue) or if option
676  FI_COLOR_ALPHA_IS_INDEX is specified, a greyscale palette is created. For a 1-bit image, only
677  if the specified background color is either black or white, a monochrome palette, consisting
678  of black and white only is created. In any case, the darker colors are stored at the smaller
679  palette indices.
680 
681  If the specified background color is not a greyscale value, or is neither black nor white
682  for a 1-bit image, solely this single color is injected into the otherwise black-initialized
683  palette. For this operation, option FI_COLOR_ALPHA_IS_INDEX is implicit, so the specified
684  color is applied to the palette entry, specified by the background color's rgbReserved
685  member. The image is then filled with this palette index.
686 
687  This function returns a newly created image as function FreeImage_Allocate does, if both
688  parameters color and palette are NULL. If only color is NULL, the palette pointed to by
689  parameter palette is initially set for the new image, if a palletized image of type
690  FIT_BITMAP is created. However, in the latter case, this function returns an image, whose
691  pixels are all initialized with zeros so, the image will be filled with the color of the
692  first palette entry.
693 
694  @param width The desired width in pixels of the new image.
695  @param height The desired height in pixels of the new image.
696  @param bpp The desired bit depth of the new image.
697  @param color A pointer to an RGBQUAD structure, that provides the color to be used for
698  filling the image.
699  @param options Options that affect the color search process for palletized images.
700  @param red_mask Specifies the bits used to store the red components of a pixel.
701  @param green_mask Specifies the bits used to store the green components of a pixel.
702  @param blue_mask Specifies the bits used to store the blue components of a pixel.
703  @return Returns a pointer to a newly allocated image on success, NULL otherwise.
704  */
705 FIBITMAP * DLL_CALLCONV
FreeImage_AllocateEx(int width,int height,int bpp,const RGBQUAD * color,int options,const RGBQUAD * palette,unsigned red_mask,unsigned green_mask,unsigned blue_mask)706 FreeImage_AllocateEx(int width, int height, int bpp, const RGBQUAD *color, int options, const RGBQUAD *palette, unsigned red_mask, unsigned green_mask, unsigned blue_mask) {
707 	return FreeImage_AllocateExT(FIT_BITMAP, width, height, bpp, ((void *)color), options, palette, red_mask, green_mask, blue_mask);
708 }
709 
710 /** @brief Enlarges or shrinks an image selectively per side and fills newly added areas
711  with the specified background color.
712 
713  This function enlarges or shrinks an image selectively per side. The main purpose of this
714  function is to add borders to an image. To add a border to any of the image's sides, a
715  positive integer value must be passed in any of the parameters left, top, right or bottom.
716  This value represents the border's width in pixels. Newly created parts of the image (the
717  border areas) are filled with the specified color. Specifying a negative integer value for
718  a certain side, will shrink or crop the image on this side. Consequently, specifying zero
719  for a certain side will not change the image's extension on that side.
720 
721  So, calling this function with all parameters left, top, right and bottom set to zero, is
722  effectively the same as calling function FreeImage_Clone; setting all parameters left, top,
723  right and bottom to value equal to or smaller than zero, my easily be substituted by a call
724  to function FreeImage_Copy. Both these cases produce a new image, which is guaranteed not to
725  be larger than the input image. Thus, since the specified color is not needed in these cases,
726  the pointer color may be NULL.
727 
728  Both parameters color and options work according to function FreeImage_FillBackground. So,
729  please refer to the documentation of FreeImage_FillBackground to learn more about parameters
730  color and options. For palletized images, the palette of the input image src is
731  transparently copied to the newly created enlarged or shrunken image, so any color
732  look-ups are performed on this palette.
733 
734  Here are some examples, that illustrate, how to use the parameters left, top, right and
735  bottom:
736 
737  // create a white color
738  RGBQUAD c;
739  c.rgbRed = 0xFF;
740  c.rgbGreen = 0xFF;
741  c.rgbBlue = 0xFF;
742  c.rgbReserved = 0x00;
743 
744  // add a white, symmetric 10 pixel wide border to the image
745  dib2 = FreeImage_EnlargeCanvas(dib, 10, 10, 10, 10, &c, FI_COLOR_IS_RGB_COLOR);
746 
747  // add white, 20 pixel wide stripes to the top and bottom side of the image
748  dib3 = FreeImage_EnlargeCanvas(dib, 0, 20, 0, 20, &c, FI_COLOR_IS_RGB_COLOR);
749 
750  // add white, 30 pixel wide stripes to the right side of the image and
751  // cut off the 40 leftmost pixel columns
752  dib3 = FreeImage_EnlargeCanvas(dib, -40, 0, 30, 0, &c, FI_COLOR_IS_RGB_COLOR);
753 
754  This function fails if either the input image is NULL or the pointer to the color is
755  NULL, while at least on of left, top, right and bottom is greater than zero. This
756  function also returns NULL, if the new image's size will be negative in either x- or
757  y-direction.
758 
759  @param dib The image to be enlarged or shrunken.
760  @param left The number of pixels, the image should be enlarged on its left side. Negative
761  values shrink the image on its left side.
762  @param top The number of pixels, the image should be enlarged on its top side. Negative
763  values shrink the image on its top side.
764  @param right The number of pixels, the image should be enlarged on its right side. Negative
765  values shrink the image on its right side.
766  @param bottom The number of pixels, the image should be enlarged on its bottom side. Negative
767  values shrink the image on its bottom side.
768  @param color The color, the enlarged sides of the image should be filled with.
769  @param options Options that affect the color search process for palletized images.
770  @return Returns a pointer to a newly allocated enlarged or shrunken image on success,
771  NULL otherwise. This function fails if either the input image is NULL or the pointer to the
772  color is NULL, while at least on of left, top, right and bottom is greater than zero. This
773  function also returns NULL, if the new image's size will be negative in either x- or
774  y-direction.
775  */
776 FIBITMAP * DLL_CALLCONV
FreeImage_EnlargeCanvas(FIBITMAP * src,int left,int top,int right,int bottom,const void * color,int options)777 FreeImage_EnlargeCanvas(FIBITMAP *src, int left, int top, int right, int bottom, const void *color, int options) {
778 
779 	if(!FreeImage_HasPixels(src)) return NULL;
780 
781 	// Just return a clone of the image, if left, top, right and bottom are
782 	// all zero.
783 	if ((left == 0) && (right == 0) && (top == 0) && (bottom == 0)) {
784 		return FreeImage_Clone(src);
785 	}
786 
787 	int width = FreeImage_GetWidth(src);
788 	int height = FreeImage_GetHeight(src);
789 
790 	// Relay on FreeImage_Copy, if all parameters left, top, right and
791 	// bottom are smaller than or equal zero. The color pointer may be
792 	// NULL in this case.
793 	if ((left <= 0) && (right <= 0) && (top <= 0) && (bottom <= 0)) {
794 		return FreeImage_Copy(src, -left, -top,	width + right, height + bottom);
795 	}
796 
797 	// From here, we need a valid color, since the image will be enlarged on
798 	// at least one side. So, fail if we don't have a valid color pointer.
799 	if (!color) {
800 		return NULL;
801 	}
802 
803 	if (((left < 0) && (-left >= width)) || ((right < 0) && (-right >= width)) ||
804 		((top < 0) && (-top >= height)) || ((bottom < 0) && (-bottom >= height))) {
805 		return NULL;
806 	}
807 
808 	unsigned newWidth = width + left + right;
809 	unsigned newHeight = height + top + bottom;
810 
811 	FREE_IMAGE_TYPE type = FreeImage_GetImageType(src);
812 	unsigned bpp = FreeImage_GetBPP(src);
813 
814 	FIBITMAP *dst = FreeImage_AllocateExT(
815 		type, newWidth, newHeight, bpp, color, options,
816 		FreeImage_GetPalette(src),
817 		FreeImage_GetRedMask(src),
818 		FreeImage_GetGreenMask(src),
819 		FreeImage_GetBlueMask(src));
820 
821 	if (!dst) {
822 		return NULL;
823 	}
824 
825 	if ((type == FIT_BITMAP) && (bpp <= 4)) {
826 		FIBITMAP *copy = FreeImage_Copy(src,
827 			((left >= 0) ? 0 : -left),
828 			((top >= 0) ? 0 : -top),
829 			((width+right)>width)?width:(width+right),
830 			((height+bottom)>height)?height:(height+bottom));
831 
832 		if (!copy) {
833 			FreeImage_Unload(dst);
834 			return NULL;
835 		}
836 
837 		if (!FreeImage_Paste(dst, copy,
838 				((left <= 0) ? 0 : left),
839 				((top <= 0) ? 0 : top), 256)) {
840 			FreeImage_Unload(copy);
841 			FreeImage_Unload(dst);
842 			return NULL;
843 		}
844 
845 		FreeImage_Unload(copy);
846 
847 	} else {
848 
849 		int bytespp = bpp / 8;
850 		BYTE *srcPtr = FreeImage_GetScanLine(src, height - 1 - ((top >= 0) ? 0 : -top));
851 		BYTE *dstPtr = FreeImage_GetScanLine(dst, newHeight - 1 - ((top <= 0) ? 0 : top));
852 
853 		unsigned srcPitch = FreeImage_GetPitch(src);
854 		unsigned dstPitch = FreeImage_GetPitch(dst);
855 
856 		int lineWidth = bytespp * (width + MIN(0, left) + MIN(0, right));
857 		int lines = height + MIN(0, top) + MIN(0, bottom);
858 
859 		if (left <= 0) {
860 			srcPtr += (-left * bytespp);
861 		} else {
862 			dstPtr += (left * bytespp);
863 		}
864 
865 		for (int i = 0; i < lines; i++) {
866 			memcpy(dstPtr, srcPtr, lineWidth);
867 			srcPtr -= srcPitch;
868 			dstPtr -= dstPitch;
869 		}
870 	}
871 
872 	// copy metadata from src to dst
873 	FreeImage_CloneMetadata(dst, src);
874 
875 	// copy transparency table
876 	FreeImage_SetTransparencyTable(dst, FreeImage_GetTransparencyTable(src), FreeImage_GetTransparencyCount(src));
877 
878 	// copy background color
879 	RGBQUAD bkcolor;
880 	if( FreeImage_GetBackgroundColor(src, &bkcolor) ) {
881 		FreeImage_SetBackgroundColor(dst, &bkcolor);
882 	}
883 
884 	// clone resolution
885 	FreeImage_SetDotsPerMeterX(dst, FreeImage_GetDotsPerMeterX(src));
886 	FreeImage_SetDotsPerMeterY(dst, FreeImage_GetDotsPerMeterY(src));
887 
888 	// clone ICC profile
889 	FIICCPROFILE *src_profile = FreeImage_GetICCProfile(src);
890 	FIICCPROFILE *dst_profile = FreeImage_CreateICCProfile(dst, src_profile->data, src_profile->size);
891 	dst_profile->flags = src_profile->flags;
892 
893 	return dst;
894 }
895 
896