1 // ==========================================================
2 // Bitmap conversion routines
3 //
4 // Design and implementation by
5 // - Floris van den Berg (flvdberg@wxs.nl)
6 // - Dale Larson (dlarson@norsesoft.com)
7 // - Herv� Drolon (drolon@infonie.fr)
8 // - Jani Kajala (janik@remedy.fi)
9 //
10 // This file is part of FreeImage 3
11 //
12 // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
13 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
14 // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
15 // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
16 // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
17 // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
18 // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
19 // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
20 // THIS DISCLAIMER.
21 //
22 // Use at your own risk!
23 // ==========================================================
24 
25 #include "FreeImage.h"
26 #include "Utilities.h"
27 
28 // ----------------------------------------------------------
29 //  internal conversions X to 24 bits
30 // ----------------------------------------------------------
31 
32 void DLL_CALLCONV
FreeImage_ConvertLine1To24(BYTE * target,BYTE * source,int width_in_pixels,RGBQUAD * palette)33 FreeImage_ConvertLine1To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
34 	for (int cols = 0; cols < width_in_pixels; cols++) {
35 		BYTE index = (source[cols >> 3] & (0x80 >> (cols & 0x07))) != 0 ? 1 : 0;
36 
37 		target[FI_RGBA_BLUE] = palette[index].rgbBlue;
38 		target[FI_RGBA_GREEN] = palette[index].rgbGreen;
39 		target[FI_RGBA_RED] = palette[index].rgbRed;
40 
41 		target += 3;
42 	}
43 }
44 
45 void DLL_CALLCONV
FreeImage_ConvertLine4To24(BYTE * target,BYTE * source,int width_in_pixels,RGBQUAD * palette)46 FreeImage_ConvertLine4To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
47 	BOOL low_nibble = FALSE;
48 	int x = 0;
49 
50 	for (int cols = 0; cols < width_in_pixels; ++cols ) {
51 		if (low_nibble) {
52 			target[FI_RGBA_BLUE] = palette[LOWNIBBLE(source[x])].rgbBlue;
53 			target[FI_RGBA_GREEN] = palette[LOWNIBBLE(source[x])].rgbGreen;
54 			target[FI_RGBA_RED] = palette[LOWNIBBLE(source[x])].rgbRed;
55 
56 			x++;
57 		} else {
58 			target[FI_RGBA_BLUE] = palette[HINIBBLE(source[x]) >> 4].rgbBlue;
59 			target[FI_RGBA_GREEN] = palette[HINIBBLE(source[x]) >> 4].rgbGreen;
60 			target[FI_RGBA_RED] = palette[HINIBBLE(source[x]) >> 4].rgbRed;
61 		}
62 
63 		low_nibble = !low_nibble;
64 
65 		target += 3;
66 	}
67 }
68 
69 void DLL_CALLCONV
FreeImage_ConvertLine8To24(BYTE * target,BYTE * source,int width_in_pixels,RGBQUAD * palette)70 FreeImage_ConvertLine8To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
71 	for (int cols = 0; cols < width_in_pixels; cols++) {
72 		target[FI_RGBA_BLUE] = palette[source[cols]].rgbBlue;
73 		target[FI_RGBA_GREEN] = palette[source[cols]].rgbGreen;
74 		target[FI_RGBA_RED] = palette[source[cols]].rgbRed;
75 
76 		target += 3;
77 	}
78 }
79 
80 void DLL_CALLCONV
FreeImage_ConvertLine16To24_555(BYTE * target,BYTE * source,int width_in_pixels)81 FreeImage_ConvertLine16To24_555(BYTE *target, BYTE *source, int width_in_pixels) {
82 	WORD *bits = (WORD *)source;
83 
84 	for (int cols = 0; cols < width_in_pixels; cols++) {
85 		target[FI_RGBA_RED]   = (BYTE)((((bits[cols] & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F);
86 		target[FI_RGBA_GREEN] = (BYTE)((((bits[cols] & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F);
87 		target[FI_RGBA_BLUE]  = (BYTE)((((bits[cols] & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F);
88 
89 		target += 3;
90 	}
91 }
92 
93 void DLL_CALLCONV
FreeImage_ConvertLine16To24_565(BYTE * target,BYTE * source,int width_in_pixels)94 FreeImage_ConvertLine16To24_565(BYTE *target, BYTE *source, int width_in_pixels) {
95 	WORD *bits = (WORD *)source;
96 
97 	for (int cols = 0; cols < width_in_pixels; cols++) {
98 		target[FI_RGBA_RED]   = (BYTE)((((bits[cols] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F);
99 		target[FI_RGBA_GREEN] = (BYTE)((((bits[cols] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F);
100 		target[FI_RGBA_BLUE]  = (BYTE)((((bits[cols] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F);
101 
102 		target += 3;
103 	}
104 }
105 
106 void DLL_CALLCONV
FreeImage_ConvertLine32To24(BYTE * target,BYTE * source,int width_in_pixels)107 FreeImage_ConvertLine32To24(BYTE *target, BYTE *source, int width_in_pixels) {
108 	for (int cols = 0; cols < width_in_pixels; cols++) {
109 		target[FI_RGBA_BLUE] = source[FI_RGBA_BLUE];
110 		target[FI_RGBA_GREEN] = source[FI_RGBA_GREEN];
111 		target[FI_RGBA_RED] = source[FI_RGBA_RED];
112 
113 		target += 3;
114 		source += 4;
115 	}
116 }
117 
118 // ----------------------------------------------------------
119 //   smart convert X to 24 bits
120 // ----------------------------------------------------------
121 
122 FIBITMAP * DLL_CALLCONV
FreeImage_ConvertTo24Bits(FIBITMAP * dib)123 FreeImage_ConvertTo24Bits(FIBITMAP *dib) {
124 	if(!FreeImage_HasPixels(dib)) return NULL;
125 
126 	const unsigned bpp = FreeImage_GetBPP(dib);
127 	const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
128 
129 	if((image_type != FIT_BITMAP) && (image_type != FIT_RGB16) && (image_type != FIT_RGBA16)) {
130 		return NULL;
131 	}
132 
133 	const int width = FreeImage_GetWidth(dib);
134 	const int height = FreeImage_GetHeight(dib);
135 
136 	if(image_type == FIT_BITMAP) {
137 		if(bpp == 24) {
138 			return FreeImage_Clone(dib);
139 		}
140 
141 		FIBITMAP *new_dib = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
142 		if(new_dib == NULL) {
143 			return NULL;
144 		}
145 
146 		// copy metadata from src to dst
147 		FreeImage_CloneMetadata(new_dib, dib);
148 
149 		switch(bpp) {
150 			case 1 :
151 			{
152 				for (int rows = 0; rows < height; rows++) {
153 					FreeImage_ConvertLine1To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
154 				}
155 				return new_dib;
156 			}
157 
158 			case 4 :
159 			{
160 				for (int rows = 0; rows < height; rows++) {
161 					FreeImage_ConvertLine4To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
162 				}
163 				return new_dib;
164 			}
165 
166 			case 8 :
167 			{
168 				for (int rows = 0; rows < height; rows++) {
169 					FreeImage_ConvertLine8To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
170 				}
171 				return new_dib;
172 			}
173 
174 			case 16 :
175 			{
176 				for (int rows = 0; rows < height; rows++) {
177 					if ((FreeImage_GetRedMask(dib) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_565_BLUE_MASK)) {
178 						FreeImage_ConvertLine16To24_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
179 					} else {
180 						// includes case where all the masks are 0
181 						FreeImage_ConvertLine16To24_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
182 					}
183 				}
184 				return new_dib;
185 			}
186 
187 			case 32 :
188 			{
189 				for (int rows = 0; rows < height; rows++) {
190 					FreeImage_ConvertLine32To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
191 				}
192 				return new_dib;
193 			}
194 		}
195 
196 	} else if(image_type == FIT_RGB16) {
197 		FIBITMAP *new_dib = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
198 		if(new_dib == NULL) {
199 			return NULL;
200 		}
201 
202 		// copy metadata from src to dst
203 		FreeImage_CloneMetadata(new_dib, dib);
204 
205 		const unsigned src_pitch = FreeImage_GetPitch(dib);
206 		const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
207 		const BYTE *src_bits = FreeImage_GetBits(dib);
208 		BYTE *dst_bits = FreeImage_GetBits(new_dib);
209 		for (int rows = 0; rows < height; rows++) {
210 			const FIRGB16 *src_pixel = (FIRGB16*)src_bits;
211 			RGBTRIPLE *dst_pixel = (RGBTRIPLE*)dst_bits;
212 			for(int cols = 0; cols < width; cols++) {
213 				dst_pixel[cols].rgbtRed   = (BYTE)(src_pixel[cols].red   >> 8);
214 				dst_pixel[cols].rgbtGreen = (BYTE)(src_pixel[cols].green >> 8);
215 				dst_pixel[cols].rgbtBlue  = (BYTE)(src_pixel[cols].blue  >> 8);
216 			}
217 			src_bits += src_pitch;
218 			dst_bits += dst_pitch;
219 		}
220 
221 		return new_dib;
222 
223 	} else if(image_type == FIT_RGBA16) {
224 		FIBITMAP *new_dib = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
225 		if(new_dib == NULL) {
226 			return NULL;
227 		}
228 
229 		// copy metadata from src to dst
230 		FreeImage_CloneMetadata(new_dib, dib);
231 
232 		const unsigned src_pitch = FreeImage_GetPitch(dib);
233 		const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
234 		const BYTE *src_bits = FreeImage_GetBits(dib);
235 		BYTE *dst_bits = FreeImage_GetBits(new_dib);
236 		for (int rows = 0; rows < height; rows++) {
237 			const FIRGBA16 *src_pixel = (FIRGBA16*)src_bits;
238 			RGBTRIPLE *dst_pixel = (RGBTRIPLE*)dst_bits;
239 			for(int cols = 0; cols < width; cols++) {
240 				dst_pixel[cols].rgbtRed   = (BYTE)(src_pixel[cols].red   >> 8);
241 				dst_pixel[cols].rgbtGreen = (BYTE)(src_pixel[cols].green >> 8);
242 				dst_pixel[cols].rgbtBlue  = (BYTE)(src_pixel[cols].blue  >> 8);
243 			}
244 			src_bits += src_pitch;
245 			dst_bits += dst_pitch;
246 		}
247 
248 		return new_dib;
249 	}
250 
251 	return NULL;
252 }
253