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