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 
29 #define RGB555(b, g, r) ((((b) >> 3) << FI16_555_BLUE_SHIFT) | (((g) >> 3) << FI16_555_GREEN_SHIFT) | (((r) >> 3) << FI16_555_RED_SHIFT))
30 
31 // ----------------------------------------------------------
32 //  internal conversions X to 16 bits (555)
33 // ----------------------------------------------------------
34 
35 void DLL_CALLCONV
FreeImage_ConvertLine1To16_555(BYTE * target,BYTE * source,int width_in_pixels,RGBQUAD * palette)36 FreeImage_ConvertLine1To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
37 	WORD *new_bits = (WORD *)target;
38 
39 	for (int cols = 0; cols < width_in_pixels; cols++) {
40 		int index = (source[cols >> 3] & (0x80 >> (cols & 0x07))) != 0 ? 1 : 0;
41 
42 		new_bits[cols] = RGB555(palette[index].rgbBlue, palette[index].rgbGreen, palette[index].rgbRed);
43 	}
44 }
45 
46 void DLL_CALLCONV
FreeImage_ConvertLine4To16_555(BYTE * target,BYTE * source,int width_in_pixels,RGBQUAD * palette)47 FreeImage_ConvertLine4To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
48 	WORD *new_bits = (WORD *)target;
49 	BOOL lonibble = FALSE;
50 	int x = 0;
51 
52 	for (int cols = 0; cols < width_in_pixels; cols++) {
53 		RGBQUAD *grab_palette;
54 
55 		if (lonibble) {
56 			grab_palette = palette + LOWNIBBLE(source[x++]);
57 		} else {
58 			grab_palette = palette + (HINIBBLE(source[x]) >> 4);
59 		}
60 
61 		new_bits[cols] = RGB555(grab_palette->rgbBlue, grab_palette->rgbGreen, grab_palette->rgbRed);
62 
63 		lonibble = !lonibble;
64 	}
65 }
66 
67 void DLL_CALLCONV
FreeImage_ConvertLine8To16_555(BYTE * target,BYTE * source,int width_in_pixels,RGBQUAD * palette)68 FreeImage_ConvertLine8To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
69 	WORD *new_bits = (WORD *)target;
70 
71 	for (int cols = 0; cols < width_in_pixels; cols++) {
72 		RGBQUAD *grab_palette = palette + source[cols];
73 
74 		new_bits[cols] = RGB555(grab_palette->rgbBlue, grab_palette->rgbGreen, grab_palette->rgbRed);
75 	}
76 }
77 
78 void DLL_CALLCONV
FreeImage_ConvertLine16_565_To16_555(BYTE * target,BYTE * source,int width_in_pixels)79 FreeImage_ConvertLine16_565_To16_555(BYTE *target, BYTE *source, int width_in_pixels) {
80 	WORD *src_bits = (WORD *)source;
81 	WORD *new_bits = (WORD *)target;
82 
83 	for (int cols = 0; cols < width_in_pixels; cols++) {
84 		new_bits[cols] = RGB555((((src_bits[cols] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F,
85 			                    (((src_bits[cols] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F,
86 								(((src_bits[cols] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F);
87 	}
88 }
89 
90 void DLL_CALLCONV
FreeImage_ConvertLine24To16_555(BYTE * target,BYTE * source,int width_in_pixels)91 FreeImage_ConvertLine24To16_555(BYTE *target, BYTE *source, int width_in_pixels) {
92 	WORD *new_bits = (WORD *)target;
93 
94 	for (int cols = 0; cols < width_in_pixels; cols++) {
95 		new_bits[cols] = RGB555(source[FI_RGBA_BLUE], source[FI_RGBA_GREEN], source[FI_RGBA_RED]);
96 
97 		source += 3;
98 	}
99 }
100 
101 void DLL_CALLCONV
FreeImage_ConvertLine32To16_555(BYTE * target,BYTE * source,int width_in_pixels)102 FreeImage_ConvertLine32To16_555(BYTE *target, BYTE *source, int width_in_pixels) {
103 	WORD *new_bits = (WORD *)target;
104 
105 	for (int cols = 0; cols < width_in_pixels; cols++) {
106 		new_bits[cols] = RGB555(source[FI_RGBA_BLUE], source[FI_RGBA_GREEN], source[FI_RGBA_RED]);
107 
108 		source += 4;
109 	}
110 }
111 
112 // ----------------------------------------------------------
113 //   smart convert X to 16 bits
114 // ----------------------------------------------------------
115 
116 FIBITMAP * DLL_CALLCONV
FreeImage_ConvertTo16Bits555(FIBITMAP * dib)117 FreeImage_ConvertTo16Bits555(FIBITMAP *dib) {
118 	if(!FreeImage_HasPixels(dib) || (FreeImage_GetImageType(dib) != FIT_BITMAP)) return NULL;
119 
120 	const int width = FreeImage_GetWidth(dib);
121 	const int height = FreeImage_GetHeight(dib);
122 	const int bpp = FreeImage_GetBPP(dib);
123 
124 	if(bpp == 16) {
125 		if ((FreeImage_GetRedMask(dib) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_565_BLUE_MASK)) {
126 			// RGB 565
127 			FIBITMAP *new_dib = FreeImage_Allocate(width, height, 16, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK);
128 			if(new_dib == NULL) {
129 				return NULL;
130 			}
131 			for (int rows = 0; rows < height; rows++) {
132 				FreeImage_ConvertLine16_565_To16_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
133 			}
134 
135 			// copy metadata from src to dst
136 			FreeImage_CloneMetadata(new_dib, dib);
137 
138 			return new_dib;
139 		} else {
140 			// RGB 555
141 			return FreeImage_Clone(dib);
142 		}
143 	}
144 	else {
145 		// other bpp cases => convert to RGB 555
146 		FIBITMAP *new_dib = FreeImage_Allocate(width, height, 16, FI16_555_RED_MASK, FI16_555_GREEN_MASK, FI16_555_BLUE_MASK);
147 		if(new_dib == NULL) {
148 			return NULL;
149 		}
150 
151 		// copy metadata from src to dst
152 		FreeImage_CloneMetadata(new_dib, dib);
153 
154 		switch (bpp) {
155 			case 1 :
156 			{
157 				for (int rows = 0; rows < height; rows++) {
158 					FreeImage_ConvertLine1To16_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
159 				}
160 
161 				return new_dib;
162 			}
163 
164 			case 4 :
165 			{
166 				for (int rows = 0; rows < height; rows++) {
167 					FreeImage_ConvertLine4To16_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
168 				}
169 
170 				return new_dib;
171 			}
172 
173 			case 8 :
174 			{
175 				for (int rows = 0; rows < height; rows++) {
176 					FreeImage_ConvertLine8To16_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
177 				}
178 
179 				return new_dib;
180 			}
181 
182 			case 24 :
183 			{
184 				for (int rows = 0; rows < height; rows++) {
185 					FreeImage_ConvertLine24To16_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
186 				}
187 
188 				return new_dib;
189 			}
190 
191 			case 32 :
192 			{
193 				for (int rows = 0; rows < height; rows++) {
194 					FreeImage_ConvertLine32To16_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
195 				}
196 
197 				return new_dib;
198 			}
199 
200 			default :
201 				// unreachable code ...
202 				FreeImage_Unload(new_dib);
203 				break;
204 
205 		}
206 	}
207 
208 	return NULL;
209 }
210