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