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