1 // ==========================================================
2 // Bitmap conversion routines
3 //
4 // Design and implementation by
5 // - Riley McNiff (rmcniff@marexgroup.com)
6 //
7 // This file is part of FreeImage 3
8 //
9 // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
10 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
11 // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
12 // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
13 // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
14 // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
15 // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
16 // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
17 // THIS DISCLAIMER.
18 //
19 // Use at your own risk!
20 // ==========================================================
21
22 #include "FreeImage.h"
23 #include "Utilities.h"
24
25 // ----------------------------------------------------------
26 // internal conversions X to 4 bits
27 // ----------------------------------------------------------
28
29 void DLL_CALLCONV
FreeImage_ConvertLine1To4(BYTE * target,BYTE * source,int width_in_pixels)30 FreeImage_ConvertLine1To4(BYTE *target, BYTE *source, int width_in_pixels) {
31 BOOL hinibble = TRUE;
32 for (int cols = 0; cols < width_in_pixels; cols++){
33 if (hinibble == TRUE){
34 target[cols >> 1] = ((source[cols >> 3] & (0x80 >> (cols & 0x07))) != 0 ? 15 : 0) << 4;
35 }
36 else {
37 target[cols >> 1] |= ((source[cols >> 3] & (0x80 >> (cols & 0x07))) != 0 ? 15 : 0);
38 }
39
40 hinibble = !hinibble;
41 }
42 }
43
44 void DLL_CALLCONV
FreeImage_ConvertLine8To4(BYTE * target,BYTE * source,int width_in_pixels,RGBQUAD * palette)45 FreeImage_ConvertLine8To4(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) {
46 BOOL hinibble = TRUE;
47 BYTE index;
48
49 for (int cols = 0; cols < width_in_pixels; cols++){
50 index = GREY(palette[source[cols]].rgbRed, palette[source[cols]].rgbGreen, palette[source[cols]].rgbBlue);
51 if (hinibble) {
52 target[cols >> 1] = (index & 0xF0);
53 } else {
54 target[cols >> 1] |= (index >> 4);
55 }
56
57 hinibble = !hinibble;
58 }
59 }
60
61 void DLL_CALLCONV
FreeImage_ConvertLine16To4_555(BYTE * target,BYTE * source,int width_in_pixels)62 FreeImage_ConvertLine16To4_555(BYTE *target, BYTE *source, int width_in_pixels) {
63 WORD *bits = (WORD *)source;
64 BOOL hinibble = TRUE;
65
66 for (int cols = 0; cols < width_in_pixels; cols++) {
67 if (hinibble) {
68 target[cols >> 1] = GREY((((bits[cols] & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F,
69 (((bits[cols] & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F,
70 (((bits[cols] & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F)
71 & 0xF0;
72 } else {
73 target[cols >> 1] |= GREY((((bits[cols] & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F,
74 (((bits[cols] & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F,
75 (((bits[cols] & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F)
76 >> 4;
77 }
78
79 hinibble = !hinibble;
80 }
81 }
82
83 void DLL_CALLCONV
FreeImage_ConvertLine16To4_565(BYTE * target,BYTE * source,int width_in_pixels)84 FreeImage_ConvertLine16To4_565(BYTE *target, BYTE *source, int width_in_pixels) {
85 WORD *bits = (WORD *)source;
86 BOOL hinibble = TRUE;
87
88 for (int cols = 0; cols < width_in_pixels; cols++) {
89 if (hinibble) {
90 target[cols >> 1] = GREY((((bits[cols] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F,
91 (((bits[cols] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F,
92 (((bits[cols] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F)
93 & 0xF0;
94 } else {
95 target[cols >> 1] |= GREY((((bits[cols] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F,
96 (((bits[cols] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F,
97 (((bits[cols] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F)
98 >> 4;
99 }
100
101 hinibble = !hinibble;
102 }
103 }
104
105 void DLL_CALLCONV
FreeImage_ConvertLine24To4(BYTE * target,BYTE * source,int width_in_pixels)106 FreeImage_ConvertLine24To4(BYTE *target, BYTE *source, int width_in_pixels) {
107 BOOL hinibble = TRUE;
108
109 for (int cols = 0; cols < width_in_pixels; cols++) {
110 if (hinibble) {
111 target[cols >> 1] = GREY(source[FI_RGBA_RED], source[FI_RGBA_GREEN], source[FI_RGBA_BLUE]) & 0xF0;
112 } else {
113 target[cols >> 1] |= GREY(source[FI_RGBA_RED], source[FI_RGBA_GREEN], source[FI_RGBA_BLUE]) >> 4;
114 }
115
116 source += 3;
117 hinibble = !hinibble;
118 }
119 }
120
121 void DLL_CALLCONV
FreeImage_ConvertLine32To4(BYTE * target,BYTE * source,int width_in_pixels)122 FreeImage_ConvertLine32To4(BYTE *target, BYTE *source, int width_in_pixels) {
123 BOOL hinibble = TRUE;
124
125 for (int cols = 0; cols < width_in_pixels; cols++) {
126 if (hinibble) {
127 target[cols >> 1] = GREY(source[FI_RGBA_RED], source[FI_RGBA_GREEN], source[FI_RGBA_BLUE]) & 0xF0;
128 } else {
129 target[cols >> 1] |= GREY(source[FI_RGBA_RED], source[FI_RGBA_GREEN], source[FI_RGBA_BLUE]) >> 4;
130 }
131
132 source += 4;
133 hinibble = !hinibble;
134 }
135 }
136
137 // ----------------------------------------------------------
138 // smart convert X to 4 bits
139 // ----------------------------------------------------------
140
141 FIBITMAP * DLL_CALLCONV
FreeImage_ConvertTo4Bits(FIBITMAP * dib)142 FreeImage_ConvertTo4Bits(FIBITMAP *dib) {
143 if(!FreeImage_HasPixels(dib)) return NULL;
144
145 const int bpp = FreeImage_GetBPP(dib);
146
147 if(bpp != 4) {
148 const int width = FreeImage_GetWidth(dib);
149 const int height = FreeImage_GetHeight(dib);
150 FIBITMAP *new_dib = FreeImage_Allocate(width, height, 4);
151
152 if(new_dib == NULL) {
153 return NULL;
154 }
155
156 // copy metadata from src to dst
157 FreeImage_CloneMetadata(new_dib, dib);
158
159 // Build a greyscale palette (*always* needed for image processing)
160
161 RGBQUAD *new_pal = FreeImage_GetPalette(new_dib);
162
163 for(int i = 0; i < 16; i++) {
164 new_pal[i].rgbRed = (BYTE)((i << 4) + i);
165 new_pal[i].rgbGreen = (BYTE)((i << 4) + i);
166 new_pal[i].rgbBlue = (BYTE)((i << 4) + i);
167 }
168
169 switch(bpp) {
170 case 1:
171 {
172 if(FreeImage_GetColorType(dib) == FIC_PALETTE) {
173
174 // Copy the palette
175
176 RGBQUAD *old_pal = FreeImage_GetPalette(dib);
177 memcpy(&new_pal[0], &old_pal[0], sizeof(RGBQUAD));
178 memcpy(&new_pal[15], &old_pal[1], sizeof(RGBQUAD));
179
180 }
181 else if(FreeImage_GetColorType(dib) == FIC_MINISWHITE) {
182
183 // Reverse the grayscale palette
184
185 for(int i = 0; i < 16; i++) {
186 new_pal[i].rgbRed = new_pal[i].rgbGreen = new_pal[i].rgbBlue = (BYTE)(255 - ((i << 4) + i));
187 }
188 }
189
190 // Expand and copy the bitmap data
191
192 for (int rows = 0; rows < height; rows++) {
193 FreeImage_ConvertLine1To4(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
194 }
195 return new_dib;
196 }
197
198 case 8 :
199 {
200 // Expand and copy the bitmap data
201
202 for (int rows = 0; rows < height; rows++) {
203 FreeImage_ConvertLine8To4(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib));
204 }
205 return new_dib;
206 }
207
208 case 16 :
209 {
210 // Expand and copy the bitmap data
211
212 for (int rows = 0; rows < height; rows++) {
213 if ((FreeImage_GetRedMask(dib) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_565_BLUE_MASK)) {
214 FreeImage_ConvertLine16To4_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
215 } else {
216 FreeImage_ConvertLine16To4_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
217 }
218 }
219
220 return new_dib;
221 }
222
223 case 24 :
224 {
225 // Expand and copy the bitmap data
226
227 for (int rows = 0; rows < height; rows++) {
228 FreeImage_ConvertLine24To4(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
229 }
230 return new_dib;
231 }
232
233 case 32 :
234 {
235 // Expand and copy the bitmap data
236
237 for (int rows = 0; rows < height; rows++) {
238 FreeImage_ConvertLine32To4(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width);
239 }
240 return new_dib;
241 }
242 }
243 }
244
245 return FreeImage_Clone(dib);
246 }
247