1 // ==========================================================
2 // Bitmap conversion routines
3 //
4 // Design and implementation by
5 // - Riley McNiff (rmcniff@marexgroup.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 // ----------------------------------------------------------
26 //  internal conversions X to 4 bits
27 // ----------------------------------------------------------
28 
29 void DLL_CALLCONV
FreeImage_ConvertLine1To4(BYTE * target,BYTE * source,int width_in_pixels)30 FreeImage_ConvertLine1To4(BYTE *target, BYTE *source, int width_in_pixels) {
31 	BOOL hinibble = TRUE;
32 	for (int cols = 0; cols < width_in_pixels; cols++){
33 		if (hinibble == TRUE){
34 			target[cols >> 1] = ((source[cols >> 3] & (0x80 >> (cols & 0x07))) != 0 ? 15 : 0) << 4;
35 		}
36 		else {
37 			target[cols >> 1] |= ((source[cols >> 3] & (0x80 >> (cols & 0x07))) != 0 ? 15 : 0);
38 		}
39 
40 		hinibble = !hinibble;
41 	}
42 }
43 
44 void DLL_CALLCONV
FreeImage_ConvertLine8To4(BYTE * target,BYTE * source,int width_in_pixels,RGBQUAD * palette)45 FreeImage_ConvertLine8To4(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
46 	BOOL hinibble = TRUE;
47 	BYTE index;
48 
49 	for (int cols = 0; cols < width_in_pixels; cols++){
50 		index = GREY(palette[source[cols]].rgbRed, palette[source[cols]].rgbGreen, palette[source[cols]].rgbBlue);
51 		if (hinibble) {
52 			target[cols >> 1] = (index & 0xF0);
53 		} else {
54 			target[cols >> 1] |= (index >> 4);
55 		}
56 
57 		hinibble = !hinibble;
58 	}
59 }
60 
61 void DLL_CALLCONV
FreeImage_ConvertLine16To4_555(BYTE * target,BYTE * source,int width_in_pixels)62 FreeImage_ConvertLine16To4_555(BYTE *target, BYTE *source, int width_in_pixels) {
63 	WORD *bits = (WORD *)source;
64 	BOOL hinibble = TRUE;
65 
66 	for (int cols = 0; cols < width_in_pixels; cols++) {
67 		if (hinibble) {
68 			target[cols >> 1] = GREY((((bits[cols] & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F,
69 								(((bits[cols] & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F,
70 								(((bits[cols] & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F)
71 								& 0xF0;
72 		} else {
73 			target[cols >> 1] |= GREY((((bits[cols] & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F,
74 								(((bits[cols] & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F,
75 								(((bits[cols] & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F)
76 								>> 4;
77 		}
78 
79 		hinibble = !hinibble;
80 	}
81 }
82 
83 void DLL_CALLCONV
FreeImage_ConvertLine16To4_565(BYTE * target,BYTE * source,int width_in_pixels)84 FreeImage_ConvertLine16To4_565(BYTE *target, BYTE *source, int width_in_pixels) {
85 	WORD *bits = (WORD *)source;
86 	BOOL hinibble = TRUE;
87 
88 	for (int cols = 0; cols < width_in_pixels; cols++) {
89 		if (hinibble) {
90 			target[cols >> 1] = GREY((((bits[cols] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F,
91 				        (((bits[cols] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F,
92 						(((bits[cols] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F)
93 						& 0xF0;
94 		} else {
95 			target[cols >> 1] |= GREY((((bits[cols] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F,
96 				        (((bits[cols] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F,
97 						(((bits[cols] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F)
98 						>> 4;
99 		}
100 
101 		hinibble = !hinibble;
102 	}
103 }
104 
105 void DLL_CALLCONV
FreeImage_ConvertLine24To4(BYTE * target,BYTE * source,int width_in_pixels)106 FreeImage_ConvertLine24To4(BYTE *target, BYTE *source, int width_in_pixels) {
107 	BOOL hinibble = TRUE;
108 
109 	for (int cols = 0; cols < width_in_pixels; cols++) {
110 		if (hinibble) {
111 			target[cols >> 1] = GREY(source[FI_RGBA_RED], source[FI_RGBA_GREEN], source[FI_RGBA_BLUE]) & 0xF0;
112 		} else {
113 			target[cols >> 1] |= GREY(source[FI_RGBA_RED], source[FI_RGBA_GREEN], source[FI_RGBA_BLUE]) >> 4;
114 		}
115 
116 		source += 3;
117 		hinibble = !hinibble;
118 	}
119 }
120 
121 void DLL_CALLCONV
FreeImage_ConvertLine32To4(BYTE * target,BYTE * source,int width_in_pixels)122 FreeImage_ConvertLine32To4(BYTE *target, BYTE *source, int width_in_pixels) {
123 	BOOL hinibble = TRUE;
124 
125 	for (int cols = 0; cols < width_in_pixels; cols++) {
126 		if (hinibble) {
127 			target[cols >> 1] = GREY(source[FI_RGBA_RED], source[FI_RGBA_GREEN], source[FI_RGBA_BLUE]) & 0xF0;
128 		} else {
129 			target[cols >> 1] |= GREY(source[FI_RGBA_RED], source[FI_RGBA_GREEN], source[FI_RGBA_BLUE]) >> 4;
130 		}
131 
132 		source += 4;
133 		hinibble = !hinibble;
134 	}
135 }
136 
137 // ----------------------------------------------------------
138 //   smart convert X to 4 bits
139 // ----------------------------------------------------------
140 
141 FIBITMAP * DLL_CALLCONV
FreeImage_ConvertTo4Bits(FIBITMAP * dib)142 FreeImage_ConvertTo4Bits(FIBITMAP *dib) {
143 	if(!FreeImage_HasPixels(dib)) return NULL;
144 
145 	const int bpp = FreeImage_GetBPP(dib);
146 
147 	if(bpp != 4) {
148 		const int width  = FreeImage_GetWidth(dib);
149 		const int height = FreeImage_GetHeight(dib);
150 		FIBITMAP *new_dib = FreeImage_Allocate(width, height, 4);
151 
152 		if(new_dib == NULL) {
153 			return NULL;
154 		}
155 
156 		// copy metadata from src to dst
157 		FreeImage_CloneMetadata(new_dib, dib);
158 
159 		// Build a greyscale palette (*always* needed for image processing)
160 
161 		RGBQUAD *new_pal = FreeImage_GetPalette(new_dib);
162 
163 		for(int i = 0; i < 16; i++) {
164 			new_pal[i].rgbRed	= (BYTE)((i << 4) + i);
165 			new_pal[i].rgbGreen = (BYTE)((i << 4) + i);
166 			new_pal[i].rgbBlue	= (BYTE)((i << 4) + i);
167 		}
168 
169 		switch(bpp) {
170 			case 1:
171 			{
172 				if(FreeImage_GetColorType(dib) == FIC_PALETTE) {
173 
174 					// Copy the palette
175 
176 					RGBQUAD *old_pal = FreeImage_GetPalette(dib);
177 					memcpy(&new_pal[0], &old_pal[0], sizeof(RGBQUAD));
178 					memcpy(&new_pal[15], &old_pal[1], sizeof(RGBQUAD));
179 
180 				}
181 				else if(FreeImage_GetColorType(dib) == FIC_MINISWHITE) {
182 
183 					// Reverse the grayscale palette
184 
185 					for(int i = 0; i < 16; i++) {
186 						new_pal[i].rgbRed = new_pal[i].rgbGreen = new_pal[i].rgbBlue = (BYTE)(255 - ((i << 4) + i));
187 					}
188 				}
189 
190 				// Expand and copy the bitmap data
191 
192 				for (int rows = 0; rows < height; rows++) {
193 					FreeImage_ConvertLine1To4(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
194 				}
195 				return new_dib;
196 			}
197 
198 			case 8 :
199 			{
200 				// Expand and copy the bitmap data
201 
202 				for (int rows = 0; rows < height; rows++) {
203 					FreeImage_ConvertLine8To4(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
204 				}
205 				return new_dib;
206 			}
207 
208 			case 16 :
209 			{
210 				// Expand and copy the bitmap data
211 
212 				for (int rows = 0; rows < height; rows++) {
213 					if ((FreeImage_GetRedMask(dib) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_565_BLUE_MASK)) {
214 						FreeImage_ConvertLine16To4_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
215 					} else {
216 						FreeImage_ConvertLine16To4_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
217 					}
218 				}
219 
220 				return new_dib;
221 			}
222 
223 			case 24 :
224 			{
225 				// Expand and copy the bitmap data
226 
227 				for (int rows = 0; rows < height; rows++) {
228 					FreeImage_ConvertLine24To4(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
229 				}
230 				return new_dib;
231 			}
232 
233 			case 32 :
234 			{
235 				// Expand and copy the bitmap data
236 
237 				for (int rows = 0; rows < height; rows++) {
238 					FreeImage_ConvertLine32To4(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
239 				}
240 				return new_dib;
241 			}
242 		}
243 	}
244 
245 	return FreeImage_Clone(dib);
246 }
247