1 // ==========================================================
2 // Bitmap conversion routines
3 //
4 // Design and implementation by
5 // - Floris van den Berg (flvdberg@wxs.nl)
6 // - Herv� Drolon (drolon@infonie.fr)
7 // - Jani Kajala (janik@remedy.fi)
8 // - Karl-Heinz Bussian (khbussian@moss.de)
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 //  internal conversions X to 8 bits
31 // ----------------------------------------------------------
32 
33 void DLL_CALLCONV
FreeImage_ConvertLine1To8(BYTE * target,BYTE * source,int width_in_pixels)34 FreeImage_ConvertLine1To8(BYTE *target, BYTE *source, int width_in_pixels) {
35 	for (unsigned cols = 0; cols < (unsigned)width_in_pixels; cols++)
36 		target[cols] = (source[cols >> 3] & (0x80 >> (cols & 0x07))) != 0 ? 255 : 0;
37 }
38 
39 void DLL_CALLCONV
FreeImage_ConvertLine4To8(BYTE * target,BYTE * source,int width_in_pixels)40 FreeImage_ConvertLine4To8(BYTE *target, BYTE *source, int width_in_pixels) {
41 	unsigned count_new = 0;
42 	unsigned count_org = 0;
43 	BOOL hinibble = TRUE;
44 
45 	while (count_new < (unsigned)width_in_pixels) {
46 		if (hinibble) {
47 			target[count_new] = (source[count_org] >> 4);
48 		} else {
49 			target[count_new] = (source[count_org] & 0x0F);
50 			count_org++;
51 		}
52 		hinibble = !hinibble;
53 		count_new++;
54 	}
55 }
56 
57 void DLL_CALLCONV
FreeImage_ConvertLine16To8_555(BYTE * target,BYTE * source,int width_in_pixels)58 FreeImage_ConvertLine16To8_555(BYTE *target, BYTE *source, int width_in_pixels) {
59 	const WORD *const bits = (WORD *)source;
60 	for (unsigned cols = 0; cols < (unsigned)width_in_pixels; cols++) {
61 		target[cols] = GREY((((bits[cols] & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F,
62 			                (((bits[cols] & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F,
63 							(((bits[cols] & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F);
64 	}
65 }
66 
67 void DLL_CALLCONV
FreeImage_ConvertLine16To8_565(BYTE * target,BYTE * source,int width_in_pixels)68 FreeImage_ConvertLine16To8_565(BYTE *target, BYTE *source, int width_in_pixels) {
69 	const WORD *const bits = (WORD *)source;
70 	for (unsigned cols = 0; cols < (unsigned)width_in_pixels; cols++) {
71 		target[cols] = GREY((((bits[cols] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F,
72 			        (((bits[cols] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F,
73 					(((bits[cols] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F);
74 	}
75 }
76 
77 void DLL_CALLCONV
FreeImage_ConvertLine24To8(BYTE * target,BYTE * source,int width_in_pixels)78 FreeImage_ConvertLine24To8(BYTE *target, BYTE *source, int width_in_pixels) {
79 	for (unsigned cols = 0; cols < (unsigned)width_in_pixels; cols++) {
80 		target[cols] = GREY(source[FI_RGBA_RED], source[FI_RGBA_GREEN], source[FI_RGBA_BLUE]);
81 		source += 3;
82 	}
83 }
84 
85 void DLL_CALLCONV
FreeImage_ConvertLine32To8(BYTE * target,BYTE * source,int width_in_pixels)86 FreeImage_ConvertLine32To8(BYTE *target, BYTE *source, int width_in_pixels) {
87 	for (unsigned cols = 0; cols < (unsigned)width_in_pixels; cols++) {
88 		target[cols] = GREY(source[FI_RGBA_RED], source[FI_RGBA_GREEN], source[FI_RGBA_BLUE]);
89 		source += 4;
90 	}
91 }
92 
93 // ----------------------------------------------------------
94 //   smart convert X to 8 bits
95 // ----------------------------------------------------------
96 
97 FIBITMAP * DLL_CALLCONV
FreeImage_ConvertTo8Bits(FIBITMAP * dib)98 FreeImage_ConvertTo8Bits(FIBITMAP *dib) {
99 	if (!FreeImage_HasPixels(dib)) {
100 		return NULL;
101 	}
102 
103 	const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
104 	if (image_type != FIT_BITMAP && image_type != FIT_UINT16) {
105 		return NULL;
106 	}
107 
108 	const unsigned bpp = FreeImage_GetBPP(dib);
109 
110 	if (bpp != 8) {
111 
112 		const unsigned width = FreeImage_GetWidth(dib);
113 		const unsigned height = FreeImage_GetHeight(dib);
114 
115 		// Allocate a destination image
116 		FIBITMAP *new_dib = FreeImage_Allocate(width, height, 8);
117 		if (new_dib == NULL) {
118 			return NULL;
119 		}
120 
121 		// Copy metadata from src to dst
122 		FreeImage_CloneMetadata(new_dib, dib);
123 
124 		// Palette of destination image has already been initialized
125 		RGBQUAD *new_pal = FreeImage_GetPalette(new_dib);
126 
127 		const FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib);
128 
129 		if (image_type == FIT_BITMAP) {
130 
131 			switch(bpp) {
132 				case 1:
133 				{
134 					if (color_type == FIC_PALETTE) {
135 						// Copy the palette
136 						RGBQUAD *old_pal = FreeImage_GetPalette(dib);
137 						new_pal[0] = old_pal[0];
138 						new_pal[255] = old_pal[1];
139 
140 					} else if (color_type == FIC_MINISWHITE) {
141 						// Create a reverse grayscale palette
142 						CREATE_GREYSCALE_PALETTE_REVERSE(new_pal, 256);
143 					}
144 
145 					// Expand and copy the bitmap data
146 					for (unsigned rows = 0; rows < height; rows++) {
147 						FreeImage_ConvertLine1To8(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
148 					}
149 					return new_dib;
150 				}
151 
152 				case 4 :
153 				{
154 					if (color_type == FIC_PALETTE) {
155 						// Copy the palette
156 						memcpy(new_pal, FreeImage_GetPalette(dib), 16 * sizeof(RGBQUAD));
157 					}
158 
159 					// Expand and copy the bitmap data
160 					for (unsigned rows = 0; rows < height; rows++) {
161 						FreeImage_ConvertLine4To8(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
162 					}
163 					return new_dib;
164 				}
165 
166 				case 16 :
167 				{
168 					// Expand and copy the bitmap data
169 					if (IS_FORMAT_RGB565(dib)) {
170 						for (unsigned rows = 0; rows < height; rows++) {
171 							FreeImage_ConvertLine16To8_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
172 						}
173 					} else {
174 						for (unsigned rows = 0; rows < height; rows++) {
175 							FreeImage_ConvertLine16To8_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
176 						}
177 					}
178 					return new_dib;
179 				}
180 
181 				case 24 :
182 				{
183 					// Expand and copy the bitmap data
184 					for (unsigned rows = 0; rows < height; rows++) {
185 						FreeImage_ConvertLine24To8(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
186 					}
187 					return new_dib;
188 				}
189 
190 				case 32 :
191 				{
192 					// Expand and copy the bitmap data
193 					for (unsigned rows = 0; rows < height; rows++) {
194 						FreeImage_ConvertLine32To8(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
195 					}
196 					return new_dib;
197 				}
198 			}
199 
200 		} else if (image_type == FIT_UINT16) {
201 
202 			const unsigned src_pitch = FreeImage_GetPitch(dib);
203 			const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
204 			const BYTE *src_bits = FreeImage_GetBits(dib);
205 			BYTE *dst_bits = FreeImage_GetBits(new_dib);
206 
207 			for (unsigned rows = 0; rows < height; rows++) {
208 				const WORD *const src_pixel = (WORD*)src_bits;
209 				BYTE *dst_pixel = (BYTE*)dst_bits;
210 				for(unsigned cols = 0; cols < width; cols++) {
211 					dst_pixel[cols] = (BYTE)(src_pixel[cols] >> 8);
212 				}
213 				src_bits += src_pitch;
214 				dst_bits += dst_pitch;
215 			}
216 			return new_dib;
217 		}
218 
219 	} // bpp != 8
220 
221 	return FreeImage_Clone(dib);
222 }
223 
224 FIBITMAP * DLL_CALLCONV
FreeImage_ConvertToGreyscale(FIBITMAP * dib)225 FreeImage_ConvertToGreyscale(FIBITMAP *dib) {
226 	if (!FreeImage_HasPixels(dib)) {
227 		return NULL;
228 	}
229 
230 	const FREE_IMAGE_COLOR_TYPE color_type = FreeImage_GetColorType(dib);
231 
232 	if (color_type == FIC_PALETTE || color_type == FIC_MINISWHITE) {
233 
234 		const unsigned bpp = FreeImage_GetBPP(dib);
235 		const unsigned width  = FreeImage_GetWidth(dib);
236 		const unsigned height = FreeImage_GetHeight(dib);
237 
238 		FIBITMAP *new_dib = FreeImage_Allocate(width, height, 8);
239 		if (new_dib == NULL) {
240 			return NULL;
241 		}
242 
243 		// Copy metadata from src to dst
244 		FreeImage_CloneMetadata(new_dib, dib);
245 
246 		// Create a greyscale palette
247 		BYTE grey_pal[256];
248 		const RGBQUAD *pal = FreeImage_GetPalette(dib);
249 		const unsigned size = CalculateUsedPaletteEntries(bpp);
250 		for (unsigned i = 0; i < size; i++) {
251 			grey_pal[i] = GREY(pal->rgbRed, pal->rgbGreen, pal->rgbBlue);
252 			pal++;
253 		}
254 
255 		const BYTE *src_bits = FreeImage_GetBits(dib);
256 		BYTE *dst_bits = FreeImage_GetBits(new_dib);
257 
258 		const unsigned src_pitch = FreeImage_GetPitch(dib);
259 		const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
260 
261 		switch(bpp) {
262 			case 1:
263 			{
264 				for (unsigned y = 0; y < height; y++) {
265 					for (unsigned x = 0; x < width; x++) {
266 						const unsigned pixel = (src_bits[x >> 3] & (0x80 >> (x & 0x07))) != 0;
267 						dst_bits[x] = grey_pal[pixel];
268 					}
269 					src_bits += src_pitch;
270 					dst_bits += dst_pitch;
271 				}
272 			}
273 			break;
274 
275 			case 4:
276 			{
277 				for (unsigned y = 0; y < height; y++) {
278 					for (unsigned x = 0; x < width; x++) {
279 						const unsigned pixel = x & 0x01 ? src_bits[x >> 1] & 0x0F : src_bits[x >> 1] >> 4;
280 						dst_bits[x] = grey_pal[pixel];
281 					}
282 					src_bits += src_pitch;
283 					dst_bits += dst_pitch;
284 				}
285 			}
286 			break;
287 
288 			case 8:
289 			{
290 				for (unsigned y = 0; y < height; y++) {
291 					for (unsigned x = 0; x < width; x++) {
292 						dst_bits[x] = grey_pal[src_bits[x]];
293 					}
294 					src_bits += src_pitch;
295 					dst_bits += dst_pitch;
296 				}
297 			}
298 			break;
299 		}
300 		return new_dib;
301 	}
302 
303 	// Convert the bitmap to 8-bit greyscale
304 	return FreeImage_ConvertTo8Bits(dib);
305 }
306