1 // ==========================================================
2 // Bitmap conversion routines
3 //
4 // Design and implementation by
5 // - Floris van den Berg (flvdberg@wxs.nl)
6 // - Dale Larson (dlarson@norsesoft.com)
7 // - Herv� Drolon (drolon@infonie.fr)
8 // - Jani Kajala (janik@remedy.fi)
9 //
10 // This file is part of FreeImage 3
11 //
12 // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
13 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
14 // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
15 // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
16 // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
17 // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
18 // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
19 // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
20 // THIS DISCLAIMER.
21 //
22 // Use at your own risk!
23 // ==========================================================
24
25 #include "FreeImage.h"
26 #include "Utilities.h"
27
28 // ----------------------------------------------------------
29 // internal conversions X to 24 bits
30 // ----------------------------------------------------------
31
32 void DLL_CALLCONV
FreeImage_ConvertLine1To24(BYTE * target,BYTE * source,int width_in_pixels,RGBQUAD * palette)33 FreeImage_ConvertLine1To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
34 for (int cols = 0; cols < width_in_pixels; cols++) {
35 BYTE index = (source[cols >> 3] & (0x80 >> (cols & 0x07))) != 0 ? 1 : 0;
36
37 target[FI_RGBA_BLUE] = palette[index].rgbBlue;
38 target[FI_RGBA_GREEN] = palette[index].rgbGreen;
39 target[FI_RGBA_RED] = palette[index].rgbRed;
40
41 target += 3;
42 }
43 }
44
45 void DLL_CALLCONV
FreeImage_ConvertLine4To24(BYTE * target,BYTE * source,int width_in_pixels,RGBQUAD * palette)46 FreeImage_ConvertLine4To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
47 BOOL low_nibble = FALSE;
48 int x = 0;
49
50 for (int cols = 0; cols < width_in_pixels; ++cols ) {
51 if (low_nibble) {
52 target[FI_RGBA_BLUE] = palette[LOWNIBBLE(source[x])].rgbBlue;
53 target[FI_RGBA_GREEN] = palette[LOWNIBBLE(source[x])].rgbGreen;
54 target[FI_RGBA_RED] = palette[LOWNIBBLE(source[x])].rgbRed;
55
56 x++;
57 } else {
58 target[FI_RGBA_BLUE] = palette[HINIBBLE(source[x]) >> 4].rgbBlue;
59 target[FI_RGBA_GREEN] = palette[HINIBBLE(source[x]) >> 4].rgbGreen;
60 target[FI_RGBA_RED] = palette[HINIBBLE(source[x]) >> 4].rgbRed;
61 }
62
63 low_nibble = !low_nibble;
64
65 target += 3;
66 }
67 }
68
69 void DLL_CALLCONV
FreeImage_ConvertLine8To24(BYTE * target,BYTE * source,int width_in_pixels,RGBQUAD * palette)70 FreeImage_ConvertLine8To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
71 for (int cols = 0; cols < width_in_pixels; cols++) {
72 target[FI_RGBA_BLUE] = palette[source[cols]].rgbBlue;
73 target[FI_RGBA_GREEN] = palette[source[cols]].rgbGreen;
74 target[FI_RGBA_RED] = palette[source[cols]].rgbRed;
75
76 target += 3;
77 }
78 }
79
80 void DLL_CALLCONV
FreeImage_ConvertLine16To24_555(BYTE * target,BYTE * source,int width_in_pixels)81 FreeImage_ConvertLine16To24_555(BYTE *target, BYTE *source, int width_in_pixels) {
82 WORD *bits = (WORD *)source;
83
84 for (int cols = 0; cols < width_in_pixels; cols++) {
85 target[FI_RGBA_RED] = (BYTE)((((bits[cols] & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F);
86 target[FI_RGBA_GREEN] = (BYTE)((((bits[cols] & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F);
87 target[FI_RGBA_BLUE] = (BYTE)((((bits[cols] & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F);
88
89 target += 3;
90 }
91 }
92
93 void DLL_CALLCONV
FreeImage_ConvertLine16To24_565(BYTE * target,BYTE * source,int width_in_pixels)94 FreeImage_ConvertLine16To24_565(BYTE *target, BYTE *source, int width_in_pixels) {
95 WORD *bits = (WORD *)source;
96
97 for (int cols = 0; cols < width_in_pixels; cols++) {
98 target[FI_RGBA_RED] = (BYTE)((((bits[cols] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F);
99 target[FI_RGBA_GREEN] = (BYTE)((((bits[cols] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F);
100 target[FI_RGBA_BLUE] = (BYTE)((((bits[cols] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F);
101
102 target += 3;
103 }
104 }
105
106 void DLL_CALLCONV
FreeImage_ConvertLine32To24(BYTE * target,BYTE * source,int width_in_pixels)107 FreeImage_ConvertLine32To24(BYTE *target, BYTE *source, int width_in_pixels) {
108 for (int cols = 0; cols < width_in_pixels; cols++) {
109 target[FI_RGBA_BLUE] = source[FI_RGBA_BLUE];
110 target[FI_RGBA_GREEN] = source[FI_RGBA_GREEN];
111 target[FI_RGBA_RED] = source[FI_RGBA_RED];
112
113 target += 3;
114 source += 4;
115 }
116 }
117
118 // ----------------------------------------------------------
119 // smart convert X to 24 bits
120 // ----------------------------------------------------------
121
122 FIBITMAP * DLL_CALLCONV
FreeImage_ConvertTo24Bits(FIBITMAP * dib)123 FreeImage_ConvertTo24Bits(FIBITMAP *dib) {
124 if(!FreeImage_HasPixels(dib)) return NULL;
125
126 const unsigned bpp = FreeImage_GetBPP(dib);
127 const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
128
129 if((image_type != FIT_BITMAP) && (image_type != FIT_RGB16) && (image_type != FIT_RGBA16)) {
130 return NULL;
131 }
132
133 const int width = FreeImage_GetWidth(dib);
134 const int height = FreeImage_GetHeight(dib);
135
136 if(image_type == FIT_BITMAP) {
137 if(bpp == 24) {
138 return FreeImage_Clone(dib);
139 }
140
141 FIBITMAP *new_dib = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
142 if(new_dib == NULL) {
143 return NULL;
144 }
145
146 // copy metadata from src to dst
147 FreeImage_CloneMetadata(new_dib, dib);
148
149 switch(bpp) {
150 case 1 :
151 {
152 for (int rows = 0; rows < height; rows++) {
153 FreeImage_ConvertLine1To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
154 }
155 return new_dib;
156 }
157
158 case 4 :
159 {
160 for (int rows = 0; rows < height; rows++) {
161 FreeImage_ConvertLine4To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
162 }
163 return new_dib;
164 }
165
166 case 8 :
167 {
168 for (int rows = 0; rows < height; rows++) {
169 FreeImage_ConvertLine8To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
170 }
171 return new_dib;
172 }
173
174 case 16 :
175 {
176 for (int rows = 0; rows < height; rows++) {
177 if ((FreeImage_GetRedMask(dib) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_565_BLUE_MASK)) {
178 FreeImage_ConvertLine16To24_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
179 } else {
180 // includes case where all the masks are 0
181 FreeImage_ConvertLine16To24_555(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_ConvertLine32To24(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
191 }
192 return new_dib;
193 }
194 }
195
196 } else if(image_type == FIT_RGB16) {
197 FIBITMAP *new_dib = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
198 if(new_dib == NULL) {
199 return NULL;
200 }
201
202 // copy metadata from src to dst
203 FreeImage_CloneMetadata(new_dib, dib);
204
205 const unsigned src_pitch = FreeImage_GetPitch(dib);
206 const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
207 const BYTE *src_bits = FreeImage_GetBits(dib);
208 BYTE *dst_bits = FreeImage_GetBits(new_dib);
209 for (int rows = 0; rows < height; rows++) {
210 const FIRGB16 *src_pixel = (FIRGB16*)src_bits;
211 RGBTRIPLE *dst_pixel = (RGBTRIPLE*)dst_bits;
212 for(int cols = 0; cols < width; cols++) {
213 dst_pixel[cols].rgbtRed = (BYTE)(src_pixel[cols].red >> 8);
214 dst_pixel[cols].rgbtGreen = (BYTE)(src_pixel[cols].green >> 8);
215 dst_pixel[cols].rgbtBlue = (BYTE)(src_pixel[cols].blue >> 8);
216 }
217 src_bits += src_pitch;
218 dst_bits += dst_pitch;
219 }
220
221 return new_dib;
222
223 } else if(image_type == FIT_RGBA16) {
224 FIBITMAP *new_dib = FreeImage_Allocate(width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
225 if(new_dib == NULL) {
226 return NULL;
227 }
228
229 // copy metadata from src to dst
230 FreeImage_CloneMetadata(new_dib, dib);
231
232 const unsigned src_pitch = FreeImage_GetPitch(dib);
233 const unsigned dst_pitch = FreeImage_GetPitch(new_dib);
234 const BYTE *src_bits = FreeImage_GetBits(dib);
235 BYTE *dst_bits = FreeImage_GetBits(new_dib);
236 for (int rows = 0; rows < height; rows++) {
237 const FIRGBA16 *src_pixel = (FIRGBA16*)src_bits;
238 RGBTRIPLE *dst_pixel = (RGBTRIPLE*)dst_bits;
239 for(int cols = 0; cols < width; cols++) {
240 dst_pixel[cols].rgbtRed = (BYTE)(src_pixel[cols].red >> 8);
241 dst_pixel[cols].rgbtGreen = (BYTE)(src_pixel[cols].green >> 8);
242 dst_pixel[cols].rgbtBlue = (BYTE)(src_pixel[cols].blue >> 8);
243 }
244 src_bits += src_pitch;
245 dst_bits += dst_pitch;
246 }
247
248 return new_dib;
249 }
250
251 return NULL;
252 }
253