/src/FreeImage/Source/FreeImage/Conversion32.cpp
C++ | 345 lines | 246 code | 52 blank | 47 comment | 63 complexity | e3d1c136c9f4b98fb66ad5e21a65081a MD5 | raw file
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// - Detlev Vendt (detlev.vendt@brillit.de) 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 32 bits 30// ---------------------------------------------------------- 31 32void DLL_CALLCONV 33FreeImage_ConvertLine1To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) { 34 for (int cols = 0; cols < width_in_pixels; cols++) { 35 int 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 target[FI_RGBA_ALPHA] = 0xFF; 41 target += 4; 42 } 43} 44 45void DLL_CALLCONV 46FreeImage_ConvertLine4To32(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[FI_RGBA_ALPHA] = 0xFF; 66 target += 4; 67 } 68} 69 70void DLL_CALLCONV 71FreeImage_ConvertLine8To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette) { 72 for (int cols = 0; cols < width_in_pixels; cols++) { 73 target[FI_RGBA_BLUE] = palette[source[cols]].rgbBlue; 74 target[FI_RGBA_GREEN] = palette[source[cols]].rgbGreen; 75 target[FI_RGBA_RED] = palette[source[cols]].rgbRed; 76 target[FI_RGBA_ALPHA] = 0xFF; 77 target += 4; 78 } 79} 80 81void DLL_CALLCONV 82FreeImage_ConvertLine16To32_555(BYTE *target, BYTE *source, int width_in_pixels) { 83 WORD *bits = (WORD *)source; 84 85 for (int cols = 0; cols < width_in_pixels; cols++) { 86 target[FI_RGBA_RED] = (BYTE)((((bits[cols] & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F); 87 target[FI_RGBA_GREEN] = (BYTE)((((bits[cols] & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F); 88 target[FI_RGBA_BLUE] = (BYTE)((((bits[cols] & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F); 89 target[FI_RGBA_ALPHA] = 0xFF; 90 target += 4; 91 } 92} 93 94void DLL_CALLCONV 95FreeImage_ConvertLine16To32_565(BYTE *target, BYTE *source, int width_in_pixels) { 96 WORD *bits = (WORD *)source; 97 98 for (int cols = 0; cols < width_in_pixels; cols++) { 99 target[FI_RGBA_RED] = (BYTE)((((bits[cols] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F); 100 target[FI_RGBA_GREEN] = (BYTE)((((bits[cols] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F); 101 target[FI_RGBA_BLUE] = (BYTE)((((bits[cols] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F); 102 target[FI_RGBA_ALPHA] = 0xFF; 103 target += 4; 104 } 105} 106/* 107void DLL_CALLCONV 108FreeImage_ConvertLine24To32(BYTE *target, BYTE *source, int width_in_pixels) { 109 for (int cols = 0; cols < width_in_pixels; cols++) { 110 *(DWORD *)target = (*(DWORD *) source & FI_RGBA_RGB_MASK) | FI_RGBA_ALPHA_MASK; 111 target += 4; 112 source += 3; 113 } 114} 115*/ 116/** 117This unoptimized version of the conversion function avoid an undetermined bug with VC++ SP6. 118The bug occurs in release mode only, when the image height is equal to 537 119(try e.g. a size of 432x537 to reproduce the bug with the optimized function). 120*/ 121void DLL_CALLCONV 122FreeImage_ConvertLine24To32(BYTE *target, BYTE *source, int width_in_pixels) { 123 for (int cols = 0; cols < width_in_pixels; cols++) { 124 target[FI_RGBA_RED] = source[FI_RGBA_RED]; 125 target[FI_RGBA_GREEN] = source[FI_RGBA_GREEN]; 126 target[FI_RGBA_BLUE] = source[FI_RGBA_BLUE]; 127 target[FI_RGBA_ALPHA] = 0xFF; 128 target += 4; 129 source += 3; 130 } 131} 132 133// ---------------------------------------------------------- 134 135inline void 136FreeImage_ConvertLine1To32MapTransparency(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette, BYTE *table, int transparent_pixels) { 137 for (int cols = 0; cols < width_in_pixels; cols++) { 138 int index = (source[cols>>3] & (0x80 >> (cols & 0x07))) != 0 ? 1 : 0; 139 140 target[FI_RGBA_BLUE] = palette[index].rgbBlue; 141 target[FI_RGBA_GREEN] = palette[index].rgbGreen; 142 target[FI_RGBA_RED] = palette[index].rgbRed; 143 target[FI_RGBA_ALPHA] = (index < transparent_pixels) ? table[index] : 255; 144 target += 4; 145 } 146} 147 148inline void 149FreeImage_ConvertLine4To32MapTransparency(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette, BYTE *table, int transparent_pixels) { 150 BOOL low_nibble = FALSE; 151 int x = 0; 152 153 for (int cols = 0 ; cols < width_in_pixels ; ++cols) { 154 if (low_nibble) { 155 target[FI_RGBA_BLUE] = palette[LOWNIBBLE(source[x])].rgbBlue; 156 target[FI_RGBA_GREEN] = palette[LOWNIBBLE(source[x])].rgbGreen; 157 target[FI_RGBA_RED] = palette[LOWNIBBLE(source[x])].rgbRed; 158 target[FI_RGBA_ALPHA] = (LOWNIBBLE(source[x]) < transparent_pixels) ? table[LOWNIBBLE(source[x])] : 255; 159 160 x++; 161 } else { 162 target[FI_RGBA_BLUE] = palette[HINIBBLE(source[x]) >> 4].rgbBlue; 163 target[FI_RGBA_GREEN] = palette[HINIBBLE(source[x]) >> 4].rgbGreen; 164 target[FI_RGBA_RED] = palette[HINIBBLE(source[x]) >> 4].rgbRed; 165 target[FI_RGBA_ALPHA] = (HINIBBLE(source[x] >> 4) < transparent_pixels) ? table[HINIBBLE(source[x]) >> 4] : 255; 166 } 167 168 low_nibble = !low_nibble; 169 170 target += 4; 171 } 172} 173 174inline void 175FreeImage_ConvertLine8To32MapTransparency(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette, BYTE *table, int transparent_pixels) { 176 for (int cols = 0; cols < width_in_pixels; cols++) { 177 target[FI_RGBA_BLUE] = palette[source[cols]].rgbBlue; 178 target[FI_RGBA_GREEN] = palette[source[cols]].rgbGreen; 179 target[FI_RGBA_RED] = palette[source[cols]].rgbRed; 180 target[FI_RGBA_ALPHA] = (source[cols] < transparent_pixels) ? table[source[cols]] : 255; 181 target += 4; 182 } 183} 184 185// ---------------------------------------------------------- 186 187FIBITMAP * DLL_CALLCONV 188FreeImage_ConvertTo32Bits(FIBITMAP *dib) { 189 if(!FreeImage_HasPixels(dib)) return NULL; 190 191 const int bpp = FreeImage_GetBPP(dib); 192 const FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); 193 194 if((image_type != FIT_BITMAP) && (image_type != FIT_RGB16) && (image_type != FIT_RGBA16)) { 195 return NULL; 196 } 197 198 const int width = FreeImage_GetWidth(dib); 199 const int height = FreeImage_GetHeight(dib); 200 201 if(image_type == FIT_BITMAP) { 202 203 if(bpp == 32) { 204 return FreeImage_Clone(dib); 205 } 206 207 FIBITMAP *new_dib = FreeImage_Allocate(width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); 208 if(new_dib == NULL) { 209 return NULL; 210 } 211 212 // copy metadata from src to dst 213 FreeImage_CloneMetadata(new_dib, dib); 214 215 BOOL bIsTransparent = FreeImage_IsTransparent(dib); 216 217 switch(bpp) { 218 case 1: 219 { 220 if(bIsTransparent) { 221 for (int rows = 0; rows < height; rows++) { 222 FreeImage_ConvertLine1To32MapTransparency(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib), FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib)); 223 } 224 } else { 225 for (int rows = 0; rows < height; rows++) { 226 FreeImage_ConvertLine1To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib)); 227 } 228 } 229 230 return new_dib; 231 } 232 233 case 4: 234 { 235 if(bIsTransparent) { 236 for (int rows = 0; rows < height; rows++) { 237 FreeImage_ConvertLine4To32MapTransparency(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib), FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib)); 238 } 239 } else { 240 for (int rows = 0; rows < height; rows++) { 241 FreeImage_ConvertLine4To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib)); 242 } 243 } 244 245 return new_dib; 246 } 247 248 case 8: 249 { 250 if(bIsTransparent) { 251 for (int rows = 0; rows < height; rows++) { 252 FreeImage_ConvertLine8To32MapTransparency(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib), FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib)); 253 } 254 } else { 255 for (int rows = 0; rows < height; rows++) { 256 FreeImage_ConvertLine8To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width, FreeImage_GetPalette(dib)); 257 } 258 } 259 260 return new_dib; 261 } 262 263 case 16: 264 { 265 for (int rows = 0; rows < height; rows++) { 266 if ((FreeImage_GetRedMask(dib) == FI16_565_RED_MASK) && (FreeImage_GetGreenMask(dib) == FI16_565_GREEN_MASK) && (FreeImage_GetBlueMask(dib) == FI16_565_BLUE_MASK)) { 267 FreeImage_ConvertLine16To32_565(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); 268 } else { 269 // includes case where all the masks are 0 270 FreeImage_ConvertLine16To32_555(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); 271 } 272 } 273 274 return new_dib; 275 } 276 277 case 24: 278 { 279 for (int rows = 0; rows < height; rows++) { 280 FreeImage_ConvertLine24To32(FreeImage_GetScanLine(new_dib, rows), FreeImage_GetScanLine(dib, rows), width); 281 } 282 283 return new_dib; 284 } 285 } 286 287 } else if(image_type == FIT_RGB16) { 288 FIBITMAP *new_dib = FreeImage_Allocate(width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); 289 if(new_dib == NULL) { 290 return NULL; 291 } 292 293 // copy metadata from src to dst 294 FreeImage_CloneMetadata(new_dib, dib); 295 296 const unsigned src_pitch = FreeImage_GetPitch(dib); 297 const unsigned dst_pitch = FreeImage_GetPitch(new_dib); 298 const BYTE *src_bits = FreeImage_GetBits(dib); 299 BYTE *dst_bits = FreeImage_GetBits(new_dib); 300 for (int rows = 0; rows < height; rows++) { 301 const FIRGB16 *src_pixel = (FIRGB16*)src_bits; 302 RGBQUAD *dst_pixel = (RGBQUAD*)dst_bits; 303 for(int cols = 0; cols < width; cols++) { 304 dst_pixel[cols].rgbRed = (BYTE)(src_pixel[cols].red >> 8); 305 dst_pixel[cols].rgbGreen = (BYTE)(src_pixel[cols].green >> 8); 306 dst_pixel[cols].rgbBlue = (BYTE)(src_pixel[cols].blue >> 8); 307 dst_pixel[cols].rgbReserved = (BYTE)0xFF; 308 } 309 src_bits += src_pitch; 310 dst_bits += dst_pitch; 311 } 312 313 return new_dib; 314 315 } else if(image_type == FIT_RGBA16) { 316 FIBITMAP *new_dib = FreeImage_Allocate(width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); 317 if(new_dib == NULL) { 318 return NULL; 319 } 320 321 // copy metadata from src to dst 322 FreeImage_CloneMetadata(new_dib, dib); 323 324 const unsigned src_pitch = FreeImage_GetPitch(dib); 325 const unsigned dst_pitch = FreeImage_GetPitch(new_dib); 326 const BYTE *src_bits = FreeImage_GetBits(dib); 327 BYTE *dst_bits = FreeImage_GetBits(new_dib); 328 for (int rows = 0; rows < height; rows++) { 329 const FIRGBA16 *src_pixel = (FIRGBA16*)src_bits; 330 RGBQUAD *dst_pixel = (RGBQUAD*)dst_bits; 331 for(int cols = 0; cols < width; cols++) { 332 dst_pixel[cols].rgbRed = (BYTE)(src_pixel[cols].red >> 8); 333 dst_pixel[cols].rgbGreen = (BYTE)(src_pixel[cols].green >> 8); 334 dst_pixel[cols].rgbBlue = (BYTE)(src_pixel[cols].blue >> 8); 335 dst_pixel[cols].rgbReserved = (BYTE)(src_pixel[cols].alpha >> 8); 336 } 337 src_bits += src_pitch; 338 dst_bits += dst_pitch; 339 } 340 341 return new_dib; 342 } 343 344 return NULL; 345}