/src/FreeImage/Source/FreeImage/J2KHelper.cpp
C++ | 500 lines | 346 code | 82 blank | 72 comment | 79 complexity | bf9d7cf11c3e1a51f8606d4418237116 MD5 | raw file
1// ========================================================== 2// JPEG2000 helpers 3// 4// Design and implementation by 5// - Hervé Drolon (drolon@infonie.fr) 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#include "../LibOpenJPEG/openjpeg.h" 25 26/** 27Divide an integer by a power of 2 and round upwards 28@return Returns a divided by 2^b 29*/ 30static int int_ceildivpow2(int a, int b) { 31 return (a + (1 << b) - 1) >> b; 32} 33 34/** 35Convert a OpenJPEG image to a FIBITMAP 36@param format_id Plugin ID 37@param image OpenJPEG image 38@return Returns the converted image if successful, returns NULL otherwise 39*/ 40FIBITMAP* J2KImageToFIBITMAP(int format_id, const opj_image_t *image) { 41 FIBITMAP *dib = NULL; 42 43 try { 44 // compute image width and height 45 46 //int w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx); 47 int wr = image->comps[0].w; 48 int wrr = int_ceildivpow2(image->comps[0].w, image->comps[0].factor); 49 50 //int h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy); 51 //int hr = image->comps[0].h; 52 int hrr = int_ceildivpow2(image->comps[0].h, image->comps[0].factor); 53 54 // check the number of components 55 56 int numcomps = image->numcomps; 57 58 BOOL bIsValid = TRUE; 59 for(int c = 0; c < numcomps - 1; c++) { 60 if( (image->comps[c].dx == image->comps[c+1].dx) && 61 (image->comps[c].dy == image->comps[c+1].dy) && 62 (image->comps[c].prec == image->comps[c+1].prec) ) { 63 continue; 64 } else { 65 bIsValid = FALSE; 66 break; 67 } 68 } 69 bIsValid &= ((numcomps == 1) || (numcomps == 3) || (numcomps == 4)); 70 if(!bIsValid) { 71 if(numcomps) { 72 FreeImage_OutputMessageProc(format_id, "Warning: image contains %d greyscale components. Only the first will be loaded.\n", numcomps); 73 numcomps = 1; 74 } else { 75 // unknown type 76 throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; 77 } 78 } 79 80 // create a new DIB 81 82 if(image->comps[0].prec <= 8) { 83 switch(numcomps) { 84 case 1: 85 dib = FreeImage_Allocate(wrr, hrr, 8); 86 break; 87 case 3: 88 dib = FreeImage_Allocate(wrr, hrr, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); 89 break; 90 case 4: 91 dib = FreeImage_Allocate(wrr, hrr, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK); 92 break; 93 } 94 } else if(image->comps[0].prec <= 16) { 95 switch(numcomps) { 96 case 1: 97 dib = FreeImage_AllocateT(FIT_UINT16, wrr, hrr); 98 break; 99 case 3: 100 dib = FreeImage_AllocateT(FIT_RGB16, wrr, hrr); 101 break; 102 case 4: 103 dib = FreeImage_AllocateT(FIT_RGBA16, wrr, hrr); 104 break; 105 } 106 } else { 107 throw FI_MSG_ERROR_UNSUPPORTED_FORMAT; 108 } 109 if(!dib) { 110 throw FI_MSG_ERROR_DIB_MEMORY; 111 } 112 113 if(image->comps[0].prec <= 8) { 114 if(numcomps == 1) { 115 // 8-bit greyscale 116 // ---------------------------------------------------------- 117 118 // build a greyscale palette 119 120 RGBQUAD *pal = FreeImage_GetPalette(dib); 121 for (int i = 0; i < 256; i++) { 122 pal[i].rgbRed = (BYTE)i; 123 pal[i].rgbGreen = (BYTE)i; 124 pal[i].rgbBlue = (BYTE)i; 125 } 126 127 // load pixel data 128 129 unsigned pixel_count = 0; 130 131 for(int y = 0; y < hrr; y++) { 132 BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y); 133 134 for(int x = 0; x < wrr; x++) { 135 const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr; 136 137 int index = image->comps[0].data[pixel_pos]; 138 index += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); 139 140 bits[x] = (BYTE)index; 141 142 pixel_count++; 143 } 144 } 145 } 146 else if(numcomps == 3) { 147 148 // 24-bit RGB 149 // ---------------------------------------------------------- 150 151 // load pixel data 152 153 unsigned pixel_count = 0; 154 155 for(int y = 0; y < hrr; y++) { 156 BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y); 157 158 for(int x = 0; x < wrr; x++) { 159 const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr; 160 161 int r = image->comps[0].data[pixel_pos]; 162 r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); 163 164 int g = image->comps[1].data[pixel_pos]; 165 g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); 166 167 int b = image->comps[2].data[pixel_pos]; 168 b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); 169 170 bits[FI_RGBA_RED] = (BYTE)r; 171 bits[FI_RGBA_GREEN] = (BYTE)g; 172 bits[FI_RGBA_BLUE] = (BYTE)b; 173 bits += 3; 174 175 pixel_count++; 176 } 177 } 178 } 179 else if(numcomps == 4) { 180 181 // 32-bit RGBA 182 // ---------------------------------------------------------- 183 184 // load pixel data 185 186 unsigned pixel_count = 0; 187 188 for(int y = 0; y < hrr; y++) { 189 BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y); 190 191 for(int x = 0; x < wrr; x++) { 192 const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr; 193 194 int r = image->comps[0].data[pixel_pos]; 195 r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); 196 197 int g = image->comps[1].data[pixel_pos]; 198 g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); 199 200 int b = image->comps[2].data[pixel_pos]; 201 b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); 202 203 int a = image->comps[3].data[pixel_pos]; 204 a += (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0); 205 206 bits[FI_RGBA_RED] = (BYTE)r; 207 bits[FI_RGBA_GREEN] = (BYTE)g; 208 bits[FI_RGBA_BLUE] = (BYTE)b; 209 bits[FI_RGBA_ALPHA] = (BYTE)a; 210 bits += 4; 211 212 pixel_count++; 213 } 214 } 215 } 216 } 217 else if(image->comps[0].prec <= 16) { 218 if(numcomps == 1) { 219 // 16-bit greyscale 220 // ---------------------------------------------------------- 221 222 // load pixel data 223 224 unsigned pixel_count = 0; 225 226 for(int y = 0; y < hrr; y++) { 227 unsigned short *bits = (unsigned short*)FreeImage_GetScanLine(dib, hrr - 1 - y); 228 229 for(int x = 0; x < wrr; x++) { 230 const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr; 231 232 int index = image->comps[0].data[pixel_pos]; 233 index += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); 234 235 bits[x] = (unsigned short)index; 236 237 pixel_count++; 238 } 239 } 240 } 241 else if(numcomps == 3) { 242 243 // 48-bit RGB 244 // ---------------------------------------------------------- 245 246 // load pixel data 247 248 unsigned pixel_count = 0; 249 250 for(int y = 0; y < hrr; y++) { 251 FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, hrr - 1 - y); 252 253 for(int x = 0; x < wrr; x++) { 254 const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr; 255 256 int r = image->comps[0].data[pixel_pos]; 257 r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); 258 259 int g = image->comps[1].data[pixel_pos]; 260 g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); 261 262 int b = image->comps[2].data[pixel_pos]; 263 b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); 264 265 bits[x].red = (WORD)r; 266 bits[x].green = (WORD)g; 267 bits[x].blue = (WORD)b; 268 269 pixel_count++; 270 } 271 } 272 } 273 else if(numcomps == 4) { 274 275 // 64-bit RGBA 276 // ---------------------------------------------------------- 277 278 // load pixel data 279 280 unsigned pixel_count = 0; 281 282 for(int y = 0; y < hrr; y++) { 283 FIRGBA16 *bits = (FIRGBA16*)FreeImage_GetScanLine(dib, hrr - 1 - y); 284 285 for(int x = 0; x < wrr; x++) { 286 const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr; 287 288 int r = image->comps[0].data[pixel_pos]; 289 r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0); 290 291 int g = image->comps[1].data[pixel_pos]; 292 g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0); 293 294 int b = image->comps[2].data[pixel_pos]; 295 b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0); 296 297 int a = image->comps[3].data[pixel_pos]; 298 a += (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0); 299 300 bits[x].red = (WORD)r; 301 bits[x].green = (WORD)g; 302 bits[x].blue = (WORD)b; 303 bits[x].alpha = (WORD)a; 304 305 pixel_count++; 306 } 307 } 308 } 309 } 310 311 return dib; 312 313 } catch(const char *text) { 314 if(dib) FreeImage_Unload(dib); 315 FreeImage_OutputMessageProc(format_id, text); 316 return NULL; 317 } 318 319} 320 321/** 322Convert a FIBITMAP to a OpenJPEG image 323@param format_id Plugin ID 324@param dib FreeImage image 325@param parameters Compression parameters 326@return Returns the converted image if successful, returns NULL otherwise 327*/ 328opj_image_t* FIBITMAPToJ2KImage(int format_id, FIBITMAP *dib, const opj_cparameters_t *parameters) { 329 int prec, numcomps, x, y, index; 330 OPJ_COLOR_SPACE color_space; 331 opj_image_cmptparm_t cmptparm[4]; // maximum of 4 components 332 opj_image_t *image = NULL; // image to encode 333 334 try { 335 int w = FreeImage_GetWidth(dib); 336 int h = FreeImage_GetHeight(dib); 337 338 // get image characteristics 339 FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib); 340 341 if(image_type == FIT_BITMAP) { 342 // standard image ... 343 prec = 8; 344 switch(FreeImage_GetColorType(dib)) { 345 case FIC_MINISBLACK: 346 numcomps = 1; 347 color_space = CLRSPC_GRAY; 348 break; 349 case FIC_RGB: 350 if(FreeImage_GetBPP(dib) == 32) { 351 // 32-bit image with a fully opaque layer 352 numcomps = 4; 353 color_space = CLRSPC_SRGB; 354 } else { 355 // 24-bit image 356 numcomps = 3; 357 color_space = CLRSPC_SRGB; 358 } 359 break; 360 case FIC_RGBALPHA: 361 numcomps = 4; 362 color_space = CLRSPC_SRGB; 363 break; 364 default: 365 return NULL; 366 } 367 } else { 368 // HDR image ... 369 prec = 16; 370 switch(image_type) { 371 case FIT_UINT16: 372 numcomps = 1; 373 color_space = CLRSPC_GRAY; 374 break; 375 case FIT_RGB16: 376 numcomps = 3; 377 color_space = CLRSPC_SRGB; 378 break; 379 case FIT_RGBA16: 380 numcomps = 4; 381 color_space = CLRSPC_SRGB; 382 break; 383 default: 384 return NULL; 385 } 386 } 387 388 // initialize image components 389 memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t)); 390 for(int i = 0; i < numcomps; i++) { 391 cmptparm[i].dx = parameters->subsampling_dx; 392 cmptparm[i].dy = parameters->subsampling_dy; 393 cmptparm[i].w = w; 394 cmptparm[i].h = h; 395 cmptparm[i].prec = prec; 396 cmptparm[i].bpp = prec; 397 cmptparm[i].sgnd = 0; 398 } 399 // create the image 400 image = opj_image_create(numcomps, &cmptparm[0], color_space); 401 if(!image) { 402 throw FI_MSG_ERROR_DIB_MEMORY; 403 } 404 405 // set image offset and reference grid 406 image->x0 = parameters->image_offset_x0; 407 image->y0 = parameters->image_offset_y0; 408 image->x1 = parameters->image_offset_x0 + (w - 1) * parameters->subsampling_dx + 1; 409 image->y1 = parameters->image_offset_y0 + (h - 1) * parameters->subsampling_dy + 1; 410 411 // set image data 412 if(prec == 8) { 413 switch(numcomps) { 414 case 1: 415 index = 0; 416 for(y = 0; y < h; y++) { 417 BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y); 418 for(x = 0; x < w; x++) { 419 image->comps[0].data[index] = bits[x]; 420 index++; 421 } 422 } 423 break; 424 case 3: 425 index = 0; 426 for(y = 0; y < h; y++) { 427 BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y); 428 for(x = 0; x < w; x++) { 429 image->comps[0].data[index] = bits[FI_RGBA_RED]; 430 image->comps[1].data[index] = bits[FI_RGBA_GREEN]; 431 image->comps[2].data[index] = bits[FI_RGBA_BLUE]; 432 bits += 3; 433 index++; 434 } 435 } 436 break; 437 case 4: 438 index = 0; 439 for(y = 0; y < h; y++) { 440 BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y); 441 for(x = 0; x < w; x++) { 442 image->comps[0].data[index] = bits[FI_RGBA_RED]; 443 image->comps[1].data[index] = bits[FI_RGBA_GREEN]; 444 image->comps[2].data[index] = bits[FI_RGBA_BLUE]; 445 image->comps[3].data[index] = bits[FI_RGBA_ALPHA]; 446 bits += 4; 447 index++; 448 } 449 } 450 break; 451 } 452 } 453 else if(prec == 16) { 454 switch(numcomps) { 455 case 1: 456 index = 0; 457 for(y = 0; y < h; y++) { 458 WORD *bits = (WORD*)FreeImage_GetScanLine(dib, h - 1 - y); 459 for(x = 0; x < w; x++) { 460 image->comps[0].data[index] = bits[x]; 461 index++; 462 } 463 } 464 break; 465 case 3: 466 index = 0; 467 for(y = 0; y < h; y++) { 468 FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, h - 1 - y); 469 for(x = 0; x < w; x++) { 470 image->comps[0].data[index] = bits[x].red; 471 image->comps[1].data[index] = bits[x].green; 472 image->comps[2].data[index] = bits[x].blue; 473 index++; 474 } 475 } 476 break; 477 case 4: 478 index = 0; 479 for(y = 0; y < h; y++) { 480 FIRGBA16 *bits = (FIRGBA16*)FreeImage_GetScanLine(dib, h - 1 - y); 481 for(x = 0; x < w; x++) { 482 image->comps[0].data[index] = bits[x].red; 483 image->comps[1].data[index] = bits[x].green; 484 image->comps[2].data[index] = bits[x].blue; 485 image->comps[3].data[index] = bits[x].alpha; 486 index++; 487 } 488 } 489 break; 490 } 491 } 492 493 return image; 494 495 } catch (const char *text) { 496 if(image) opj_image_destroy(image); 497 FreeImage_OutputMessageProc(format_id, text); 498 return NULL; 499 } 500}