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 //
9 // This file is part of FreeImage 3
10 //
11 // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
12 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
13 // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
14 // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
15 // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
16 // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
17 // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
18 // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
19 // THIS DISCLAIMER.
20 //
21 // Use at your own risk!
22 // ==========================================================
23 
24 #include "FreeImage.h"
25 #include "Utilities.h"
26 
27 // ----------------------------------------------------------
28 //  internal conversions X to 16 bits (565)
29 // ----------------------------------------------------------
30 
31 void DLL_CALLCONV
FreeImage_ConvertLine1To16_565(BYTE * target,BYTE * source,int width_in_pixels,RGBQUAD * palette)32 FreeImage_ConvertLine1To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
33 	WORD *new_bits = (WORD *)target;
34 
35 	for (int cols = 0; cols < width_in_pixels; cols++) {
36 		int index = (source[cols >> 3] & (0x80 >> (cols & 0x07))) != 0 ? 1 : 0;
37 
38 		new_bits[cols] = RGB565(palette[index].rgbBlue, palette[index].rgbGreen, palette[index].rgbRed);
39 	}
40 }
41 
42 void DLL_CALLCONV
FreeImage_ConvertLine4To16_565(BYTE * target,BYTE * source,int width_in_pixels,RGBQUAD * palette)43 FreeImage_ConvertLine4To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
44 	WORD *new_bits = (WORD *)target;
45 	BOOL lonibble = FALSE;
46 	int x = 0;
47 
48 	for (int cols = 0; cols < width_in_pixels; cols++) {
49 		RGBQUAD *grab_palette;
50 
51 		if (lonibble) {
52 			grab_palette = palette + LOWNIBBLE(source[x++]);
53 		} else {
54 			grab_palette = palette + (HINIBBLE(source[x]) >> 4);
55 		}
56 
57 		new_bits[cols] = RGB565(grab_palette->rgbBlue, grab_palette->rgbGreen, grab_palette->rgbRed);
58 
59 		lonibble = !lonibble;
60 	}
61 }
62 
63 void DLL_CALLCONV
FreeImage_ConvertLine8To16_565(BYTE * target,BYTE * source,int width_in_pixels,RGBQUAD * palette)64 FreeImage_ConvertLine8To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
65 	WORD *new_bits = (WORD *)target;
66 
67 	for (int cols = 0; cols < width_in_pixels; cols++) {
68 		RGBQUAD *grab_palette = palette + source[cols];
69 
70 		new_bits[cols] = RGB565(grab_palette->rgbBlue, grab_palette->rgbGreen, grab_palette->rgbRed);
71 	}
72 }
73 
74 void DLL_CALLCONV
FreeImage_ConvertLine16_555_To16_565(BYTE * target,BYTE * source,int width_in_pixels)75 FreeImage_ConvertLine16_555_To16_565(BYTE *target, BYTE *source, int width_in_pixels) {
76 	WORD *src_bits = (WORD *)source;
77 	WORD *new_bits = (WORD *)target;
78 
79 	for (int cols = 0; cols < width_in_pixels; cols++) {
80 		new_bits[cols] = RGB565((((src_bits[cols] & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F,
81 			                    (((src_bits[cols] & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F,
82 								(((src_bits[cols] & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F);
83 	}
84 }
85 
86 void DLL_CALLCONV
FreeImage_ConvertLine24To16_565(BYTE * target,BYTE * source,int width_in_pixels)87 FreeImage_ConvertLine24To16_565(BYTE *target, BYTE *source, int width_in_pixels) {
88 	WORD *new_bits = (WORD *)target;
89 
90 	for (int cols = 0; cols < width_in_pixels; cols++) {
91 		new_bits[cols] = RGB565(source[FI_RGBA_BLUE], source[FI_RGBA_GREEN], source[FI_RGBA_RED]);
92 
93 		source += 3;
94 	}
95 }
96 
97 void DLL_CALLCONV
FreeImage_ConvertLine32To16_565(BYTE * target,BYTE * source,int width_in_pixels)98 FreeImage_ConvertLine32To16_565(BYTE *target, BYTE *source, int width_in_pixels) {
99 	WORD *new_bits = (WORD *)target;
100 
101 	for (int cols = 0; cols < width_in_pixels; cols++) {
102 		new_bits[cols] = RGB565(source[FI_RGBA_BLUE], source[FI_RGBA_GREEN], source[FI_RGBA_RED]);
103 
104 		source += 4;
105 	}
106 }
107 
108 // ----------------------------------------------------------
109 //   smart convert X to 16 bits (565)
110 // ----------------------------------------------------------
111 
112 FIBITMAP * DLL_CALLCONV
FreeImage_ConvertTo16Bits565(FIBITMAP * dib)113 FreeImage_ConvertTo16Bits565(FIBITMAP *dib) {
114 	if(!FreeImage_HasPixels(dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP)) return NULL;
115 
116 	const int width = FreeImage_GetWidth(dib);
117 	const int height = FreeImage_GetHeight(dib);
118 	const int bpp = FreeImage_GetBPP(dib);
119 
120 	if(bpp == 16) {
121 		if ((FreeImage_GetRedMask(dib) == FI16_555_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_555_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_555_BLUE_MASK)) {
122 			// RGB 555
123 			FIBITMAP *new_dib = FreeImage_Allocate(width, height, 16, FI16_565_RED_MASK, FI16_565_GREEN_MASK, FI16_565_BLUE_MASK);
124 			if(new_dib == NULL) {
125 				return NULL;
126 			}
127 			for (int rows = 0; rows < height; rows++) {
128 				FreeImage_ConvertLine16_555_To16_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
129 			}
130 
131 			// copy metadata from src to dst
132 			FreeImage_CloneMetadata(new_dib, dib);
133 
134 			return new_dib;
135 		} else {
136 			// RGB 565
137 			return FreeImage_Clone(dib);
138 		}
139 	}
140 	else {
141 		// other bpp cases => convert to RGB 565
142 		FIBITMAP *new_dib = FreeImage_Allocate(width, height, 16, FI16_565_RED_MASK, FI16_565_GREEN_MASK, FI16_565_BLUE_MASK);
143 		if(new_dib == NULL) {
144 			return NULL;
145 		}
146 
147 		// copy metadata from src to dst
148 		FreeImage_CloneMetadata(new_dib, dib);
149 
150 		switch (bpp) {
151 			case 1 :
152 			{
153 				for (int rows = 0; rows < height; rows++) {
154 					FreeImage_ConvertLine1To16_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
155 				}
156 
157 				return new_dib;
158 			}
159 
160 			case 4 :
161 			{
162 				for (int rows = 0; rows < height; rows++) {
163 					FreeImage_ConvertLine4To16_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
164 				}
165 
166 				return new_dib;
167 			}
168 
169 			case 8 :
170 			{
171 				for (int rows = 0; rows < height; rows++) {
172 					FreeImage_ConvertLine8To16_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
173 				}
174 
175 				return new_dib;
176 			}
177 
178 			case 24 :
179 			{
180 				for (int rows = 0; rows < height; rows++) {
181 					FreeImage_ConvertLine24To16_565(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_ConvertLine32To16_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
191 				}
192 
193 				return new_dib;
194 			}
195 
196 			default :
197 				// unreachable code ...
198 				FreeImage_Unload(new_dib);
199 				break;
200 		}
201 	}
202 
203 	return NULL;
204 }
205