Coverage Report

Created: 2025-12-02 06:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeimage-svn/FreeImage/trunk/Source/FreeImage/J2KHelper.cpp
Line
Count
Source
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
#include "J2KHelper.h"
26
27
// --------------------------------------------------------------------------
28
29
static OPJ_UINT64 
30
0
_LengthProc(J2KFIO_t *fio) {
31
0
  long start_pos = fio->io->tell_proc(fio->handle);
32
0
  fio->io->seek_proc(fio->handle, 0, SEEK_END);
33
0
  unsigned file_length = fio->io->tell_proc(fio->handle) - start_pos;
34
0
  fio->io->seek_proc(fio->handle, start_pos, SEEK_SET);
35
0
  return (OPJ_UINT64)file_length;
36
0
}
37
38
static OPJ_SIZE_T 
39
0
_ReadProc(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data) {
40
0
  J2KFIO_t *fio = (J2KFIO_t*)p_user_data;
41
0
  OPJ_SIZE_T l_nb_read = fio->io->read_proc(p_buffer, 1, (unsigned)p_nb_bytes, fio->handle);
42
0
  return l_nb_read ? l_nb_read : (OPJ_SIZE_T)-1;
43
0
}
44
45
static OPJ_SIZE_T 
46
0
_WriteProc(void *p_buffer, OPJ_SIZE_T p_nb_bytes, void *p_user_data) {
47
0
  J2KFIO_t *fio = (J2KFIO_t*)p_user_data;  
48
0
  return fio->io->write_proc(p_buffer, 1, (unsigned)p_nb_bytes, fio->handle);
49
0
}
50
51
static OPJ_OFF_T 
52
0
_SkipProc(OPJ_OFF_T p_nb_bytes, void *p_user_data) {
53
0
  J2KFIO_t *fio = (J2KFIO_t*)p_user_data;
54
0
  if( fio->io->seek_proc(fio->handle, (long)p_nb_bytes, SEEK_CUR) ) {
55
0
    return -1;
56
0
  }
57
0
  return p_nb_bytes;
58
0
}
59
60
static OPJ_BOOL 
61
0
_SeekProc(OPJ_OFF_T p_nb_bytes, FILE * p_user_data) {
62
0
  J2KFIO_t *fio = (J2KFIO_t*)p_user_data;
63
0
  if( fio->io->seek_proc(fio->handle, (long)p_nb_bytes, SEEK_SET) ) {
64
0
    return OPJ_FALSE;
65
0
  }
66
0
  return OPJ_TRUE;
67
0
}
68
69
// --------------------------------------------------------------------------
70
71
J2KFIO_t* 
72
0
opj_freeimage_stream_create(FreeImageIO *io, fi_handle handle, BOOL bRead) {
73
0
  if(!handle) {
74
0
    return NULL;
75
0
  }
76
0
  J2KFIO_t *fio = (J2KFIO_t*)malloc(sizeof(J2KFIO_t));
77
0
  if(fio) {
78
0
    fio->io = io;
79
0
    fio->handle = handle;
80
81
0
    opj_stream_t *l_stream = opj_stream_create(OPJ_J2K_STREAM_CHUNK_SIZE, bRead ? OPJ_TRUE : OPJ_FALSE);
82
0
    if (l_stream) {
83
0
      opj_stream_set_user_data(l_stream, fio, NULL);
84
0
      opj_stream_set_user_data_length(l_stream, _LengthProc(fio));
85
0
      opj_stream_set_read_function(l_stream, (opj_stream_read_fn)_ReadProc);
86
0
      opj_stream_set_write_function(l_stream, (opj_stream_write_fn)_WriteProc);
87
0
      opj_stream_set_skip_function(l_stream, (opj_stream_skip_fn)_SkipProc);
88
0
      opj_stream_set_seek_function(l_stream, (opj_stream_seek_fn)_SeekProc);
89
0
      fio->stream = l_stream;
90
0
      return fio;
91
0
    } else {
92
0
      free(fio);
93
0
    }
94
0
  }
95
96
0
  return NULL;   
97
0
}
98
99
void 
100
0
opj_freeimage_stream_destroy(J2KFIO_t* fio) {
101
0
  if(fio) {
102
0
    if(fio->stream) {
103
0
      opj_stream_destroy(fio->stream);
104
0
    }
105
0
    free(fio);
106
0
  }
107
0
}
108
109
// --------------------------------------------------------------------------
110
111
/**
112
Divide an integer by a power of 2 and round upwards
113
@return Returns a divided by 2^b
114
*/
115
0
static int int_ceildivpow2(int a, int b) {
116
0
  return (a + (1 << b) - 1) >> b;
117
0
}
118
119
/**
120
Convert a OpenJPEG image to a FIBITMAP
121
@param format_id Plugin ID
122
@param image OpenJPEG image
123
@param header_only If TRUE, allocate a 'header only' FIBITMAP, otherwise allocate a full FIBITMAP
124
@return Returns the converted image if successful, returns NULL otherwise
125
*/
126
0
FIBITMAP* J2KImageToFIBITMAP(int format_id, const opj_image_t *image, BOOL header_only) {
127
0
  FIBITMAP *dib = NULL;
128
129
0
  try {
130
    // check the number of components
131
0
    int numcomps = image->numcomps;
132
0
    if (numcomps < 1) {
133
0
      throw FI_MSG_ERROR_CORRUPTED_IMAGE;
134
0
    }
135
136
    // compute image width and height
137
138
    //int w = int_ceildiv(image->x1 - image->x0, image->comps[0].dx);
139
0
    int wr = image->comps[0].w;
140
0
    int wrr = int_ceildivpow2(image->comps[0].w, image->comps[0].factor);
141
    
142
    //int h = int_ceildiv(image->y1 - image->y0, image->comps[0].dy);
143
    //int hr = image->comps[0].h;
144
0
    int hrr = int_ceildivpow2(image->comps[0].h, image->comps[0].factor);
145
146
0
    BOOL bIsValid = TRUE;
147
0
    for(int c = 0; c < numcomps - 1; c++) {
148
0
      if( (image->comps[c].dx == image->comps[c+1].dx) && 
149
0
        (image->comps[c].dy == image->comps[c+1].dy) &&
150
0
        (image->comps[c].prec == image->comps[c+1].prec) ) {
151
0
        continue;
152
0
      } else {
153
0
        bIsValid = FALSE;
154
0
        break;
155
0
      }
156
0
    }
157
0
    bIsValid &= ((numcomps == 1) || (numcomps == 3) || (numcomps == 4));
158
0
    if(!bIsValid) {
159
0
      if(numcomps) {
160
0
        FreeImage_OutputMessageProc(format_id, "Warning: image contains %d greyscale components. Only the first will be loaded.\n", numcomps);
161
0
        numcomps = 1;
162
0
      } else {
163
        // unknown type
164
0
        throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
165
0
      }
166
0
    }
167
168
    // create a new DIB
169
170
0
    if(image->comps[0].prec <= 8) {
171
0
      switch(numcomps) {
172
0
        case 1:
173
0
          dib = FreeImage_AllocateHeader(header_only, wrr, hrr, 8);
174
0
          break;
175
0
        case 3:
176
0
          dib = FreeImage_AllocateHeader(header_only, wrr, hrr, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
177
0
          break;
178
0
        case 4:
179
0
          dib = FreeImage_AllocateHeader(header_only, wrr, hrr, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
180
0
          break;
181
0
      }
182
0
    } else if(image->comps[0].prec <= 16) {
183
0
      switch(numcomps) {
184
0
        case 1:
185
0
          dib = FreeImage_AllocateHeaderT(header_only, FIT_UINT16, wrr, hrr);
186
0
          break;
187
0
        case 3:
188
0
          dib = FreeImage_AllocateHeaderT(header_only, FIT_RGB16, wrr, hrr);
189
0
          break;
190
0
        case 4:
191
0
          dib = FreeImage_AllocateHeaderT(header_only, FIT_RGBA16, wrr, hrr);
192
0
          break;
193
0
      }
194
0
    } else {
195
0
      throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
196
0
    }
197
0
    if(!dib) {
198
0
      throw FI_MSG_ERROR_DIB_MEMORY;
199
0
    }
200
201
    // "header only" FIBITMAP ?
202
0
    if(header_only) {
203
0
      return dib;
204
0
    }
205
    
206
0
    if(image->comps[0].prec <= 8) {
207
0
      if(numcomps == 1) {
208
        // 8-bit greyscale
209
        // ----------------------------------------------------------
210
211
        // build a greyscale palette
212
        
213
0
        RGBQUAD *pal = FreeImage_GetPalette(dib);
214
0
        for (int i = 0; i < 256; i++) {
215
0
          pal[i].rgbRed = (BYTE)i;
216
0
          pal[i].rgbGreen = (BYTE)i;
217
0
          pal[i].rgbBlue  = (BYTE)i;
218
0
        }
219
220
        // load pixel data
221
222
0
        unsigned pixel_count = 0;
223
224
0
        for(int y = 0; y < hrr; y++) {   
225
0
          BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y);
226
227
0
          for(int x = 0; x < wrr; x++) {
228
0
            const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
229
230
0
            int index = image->comps[0].data[pixel_pos];
231
0
            index += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
232
233
0
            bits[x] = (BYTE)index;
234
235
0
            pixel_count++;
236
0
          }
237
0
        }
238
0
      }
239
0
      else if(numcomps == 3) {
240
241
        // 24-bit RGB
242
        // ---------------------------------------------------------- 
243
        
244
        // load pixel data
245
246
0
        unsigned pixel_count = 0;
247
248
0
        for(int y = 0; y < hrr; y++) {   
249
0
          BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y);
250
251
0
          for(int x = 0; x < wrr; x++) {
252
0
            const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
253
254
0
            int r = image->comps[0].data[pixel_pos];
255
0
            r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
256
            
257
0
            int g = image->comps[1].data[pixel_pos];
258
0
            g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
259
            
260
0
            int b = image->comps[2].data[pixel_pos];
261
0
            b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
262
263
0
            bits[FI_RGBA_RED]   = (BYTE)r;
264
0
            bits[FI_RGBA_GREEN] = (BYTE)g;
265
0
            bits[FI_RGBA_BLUE]  = (BYTE)b;
266
0
            bits += 3;
267
268
0
            pixel_count++;
269
0
          }
270
0
        }
271
0
      }
272
0
      else if(numcomps == 4) {
273
274
        // 32-bit RGBA
275
        // ---------------------------------------------------------- 
276
        
277
        // load pixel data
278
279
0
        unsigned pixel_count = 0;
280
281
0
        for(int y = 0; y < hrr; y++) {   
282
0
          BYTE *bits = FreeImage_GetScanLine(dib, hrr - 1 - y);
283
284
0
          for(int x = 0; x < wrr; x++) {
285
0
            const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
286
287
0
            int r = image->comps[0].data[pixel_pos];
288
0
            r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
289
            
290
0
            int g = image->comps[1].data[pixel_pos];
291
0
            g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
292
            
293
0
            int b = image->comps[2].data[pixel_pos];
294
0
            b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
295
296
0
            int a = image->comps[3].data[pixel_pos];
297
0
            a += (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0);
298
299
0
            bits[FI_RGBA_RED]   = (BYTE)r;
300
0
            bits[FI_RGBA_GREEN] = (BYTE)g;
301
0
            bits[FI_RGBA_BLUE]  = (BYTE)b;
302
0
            bits[FI_RGBA_ALPHA] = (BYTE)a;
303
0
            bits += 4;
304
305
0
            pixel_count++;
306
0
          }
307
0
        }
308
0
      }
309
0
    }
310
0
    else if(image->comps[0].prec <= 16) {
311
0
      if(numcomps == 1) {
312
        // 16-bit greyscale
313
        // ----------------------------------------------------------
314
315
        // load pixel data
316
317
0
        unsigned pixel_count = 0;
318
319
0
        for(int y = 0; y < hrr; y++) {   
320
0
          WORD *bits = (WORD*)FreeImage_GetScanLine(dib, hrr - 1 - y);
321
322
0
          for(int x = 0; x < wrr; x++) {
323
0
            const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
324
325
0
            int index = image->comps[0].data[pixel_pos];
326
0
            index += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
327
328
0
            bits[x] = (WORD)index;
329
330
0
            pixel_count++;
331
0
          }
332
0
        }
333
0
      }
334
0
      else if(numcomps == 3) {
335
336
        // 48-bit RGB
337
        // ---------------------------------------------------------- 
338
        
339
        // load pixel data
340
341
0
        unsigned pixel_count = 0;
342
343
0
        for(int y = 0; y < hrr; y++) {   
344
0
          FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, hrr - 1 - y);
345
346
0
          for(int x = 0; x < wrr; x++) {
347
0
            const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
348
349
0
            int r = image->comps[0].data[pixel_pos];
350
0
            r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
351
            
352
0
            int g = image->comps[1].data[pixel_pos];
353
0
            g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
354
            
355
0
            int b = image->comps[2].data[pixel_pos];
356
0
            b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
357
358
0
            bits[x].red   = (WORD)r;
359
0
            bits[x].green = (WORD)g;
360
0
            bits[x].blue  = (WORD)b;
361
362
0
            pixel_count++;
363
0
          }
364
0
        }
365
0
      }
366
0
      else if(numcomps == 4) {
367
368
        // 64-bit RGBA
369
        // ---------------------------------------------------------- 
370
        
371
        // load pixel data
372
373
0
        unsigned pixel_count = 0;
374
375
0
        for(int y = 0; y < hrr; y++) {   
376
0
          FIRGBA16 *bits = (FIRGBA16*)FreeImage_GetScanLine(dib, hrr - 1 - y);
377
378
0
          for(int x = 0; x < wrr; x++) {
379
0
            const unsigned pixel_pos = pixel_count / wrr * wr + pixel_count % wrr;
380
381
0
            int r = image->comps[0].data[pixel_pos];
382
0
            r += (image->comps[0].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
383
            
384
0
            int g = image->comps[1].data[pixel_pos];
385
0
            g += (image->comps[1].sgnd ? 1 << (image->comps[1].prec - 1) : 0);
386
            
387
0
            int b = image->comps[2].data[pixel_pos];
388
0
            b += (image->comps[2].sgnd ? 1 << (image->comps[2].prec - 1) : 0);
389
390
0
            int a = image->comps[3].data[pixel_pos];
391
0
            a += (image->comps[3].sgnd ? 1 << (image->comps[3].prec - 1) : 0);
392
393
0
            bits[x].red   = (WORD)r;
394
0
            bits[x].green = (WORD)g;
395
0
            bits[x].blue  = (WORD)b;
396
0
            bits[x].alpha = (WORD)a;
397
398
0
            pixel_count++;
399
0
          }
400
0
        }
401
0
      }
402
0
    }
403
404
0
    return dib;
405
406
0
  } catch(const char *text) {
407
0
    if(dib) FreeImage_Unload(dib);
408
0
    FreeImage_OutputMessageProc(format_id, text);
409
0
    return NULL;
410
0
  }
411
412
0
}
413
414
/**
415
Convert a FIBITMAP to a OpenJPEG image
416
@param format_id Plugin ID
417
@param dib FreeImage image
418
@param parameters Compression parameters
419
@return Returns the converted image if successful, returns NULL otherwise
420
*/
421
0
opj_image_t* FIBITMAPToJ2KImage(int format_id, FIBITMAP *dib, const opj_cparameters_t *parameters) {
422
0
  int prec, numcomps, x, y, index;
423
0
  OPJ_COLOR_SPACE color_space;
424
0
  opj_image_cmptparm_t cmptparm[4]; // maximum of 4 components 
425
0
  opj_image_t *image = NULL;     // image to encode
426
427
0
  try {
428
0
    int w = FreeImage_GetWidth(dib);
429
0
    int h = FreeImage_GetHeight(dib);
430
431
    // get image characteristics
432
0
    FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
433
434
0
    if(image_type == FIT_BITMAP) {
435
      // standard image ...
436
0
      prec = 8;
437
0
      switch(FreeImage_GetColorType(dib)) {
438
0
        case FIC_MINISBLACK:
439
0
          numcomps = 1;
440
0
          color_space = OPJ_CLRSPC_GRAY;
441
0
          break;
442
0
        case FIC_RGB:
443
0
          if(FreeImage_GetBPP(dib) == 32) {
444
            // 32-bit image with a fully opaque layer
445
0
            numcomps = 4;
446
0
            color_space = OPJ_CLRSPC_SRGB;
447
0
          } else {
448
            // 24-bit image
449
0
            numcomps = 3;
450
0
            color_space = OPJ_CLRSPC_SRGB;
451
0
          }
452
0
          break;
453
0
        case FIC_RGBALPHA:
454
0
          numcomps = 4;
455
0
          color_space = OPJ_CLRSPC_SRGB;
456
0
          break;
457
0
        default:
458
0
          return NULL;
459
0
      }
460
0
    } else {
461
      // HDR image ...
462
0
      prec = 16;
463
0
      switch(image_type) {
464
0
        case FIT_UINT16:
465
0
          numcomps = 1;
466
0
          color_space = OPJ_CLRSPC_GRAY;
467
0
          break;
468
0
        case FIT_RGB16:
469
0
          numcomps = 3;
470
0
          color_space = OPJ_CLRSPC_SRGB;
471
0
          break;
472
0
        case FIT_RGBA16:
473
0
          numcomps = 4;
474
0
          color_space = OPJ_CLRSPC_SRGB;
475
0
          break;
476
0
        default:
477
0
          return NULL;
478
0
      }
479
0
    }
480
481
    // initialize image components 
482
0
    memset(&cmptparm[0], 0, 4 * sizeof(opj_image_cmptparm_t));
483
0
    for(int i = 0; i < numcomps; i++) {
484
0
      cmptparm[i].dx = parameters->subsampling_dx;
485
0
      cmptparm[i].dy = parameters->subsampling_dy;
486
0
      cmptparm[i].w = w;
487
0
      cmptparm[i].h = h;
488
0
      cmptparm[i].prec = prec;
489
0
      cmptparm[i].bpp = prec;
490
0
      cmptparm[i].sgnd = 0;
491
0
    }
492
    // create the image 
493
0
    image = opj_image_create(numcomps, &cmptparm[0], color_space);
494
0
    if(!image) {
495
0
      throw FI_MSG_ERROR_DIB_MEMORY;
496
0
    }
497
498
    // set image offset and reference grid 
499
0
    image->x0 = parameters->image_offset_x0;
500
0
    image->y0 = parameters->image_offset_y0;
501
0
    image->x1 = parameters->image_offset_x0 + (w - 1) * parameters->subsampling_dx + 1;
502
0
    image->y1 = parameters->image_offset_y0 + (h - 1) * parameters->subsampling_dy + 1;
503
504
    // set image data 
505
0
    if(prec == 8) {
506
0
      switch(numcomps) {
507
0
        case 1:
508
0
          index = 0;
509
0
          for(y = 0; y < h; y++) {
510
0
            BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y);
511
0
            for(x = 0; x < w; x++) {
512
0
              image->comps[0].data[index] = bits[x];
513
0
              index++;
514
0
            }
515
0
          }
516
0
          break;
517
0
        case 3:
518
0
          index = 0;
519
0
          for(y = 0; y < h; y++) {
520
0
            BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y);
521
0
            for(x = 0; x < w; x++) {
522
0
              image->comps[0].data[index] = bits[FI_RGBA_RED];
523
0
              image->comps[1].data[index] = bits[FI_RGBA_GREEN];
524
0
              image->comps[2].data[index] = bits[FI_RGBA_BLUE];
525
0
              bits += 3;
526
0
              index++;
527
0
            }
528
0
          }
529
0
          break;
530
0
        case 4:
531
0
          index = 0;
532
0
          for(y = 0; y < h; y++) {
533
0
            BYTE *bits = FreeImage_GetScanLine(dib, h - 1 - y);
534
0
            for(x = 0; x < w; x++) {
535
0
              image->comps[0].data[index] = bits[FI_RGBA_RED];
536
0
              image->comps[1].data[index] = bits[FI_RGBA_GREEN];
537
0
              image->comps[2].data[index] = bits[FI_RGBA_BLUE];
538
0
              image->comps[3].data[index] = bits[FI_RGBA_ALPHA];
539
0
              bits += 4;
540
0
              index++;
541
0
            }
542
0
          }
543
0
          break;
544
0
      }
545
0
    }
546
0
    else if(prec == 16) {
547
0
      switch(numcomps) {
548
0
        case 1:
549
0
          index = 0;
550
0
          for(y = 0; y < h; y++) {
551
0
            WORD *bits = (WORD*)FreeImage_GetScanLine(dib, h - 1 - y);
552
0
            for(x = 0; x < w; x++) {
553
0
              image->comps[0].data[index] = bits[x];
554
0
              index++;
555
0
            }
556
0
          }
557
0
          break;
558
0
        case 3:
559
0
          index = 0;
560
0
          for(y = 0; y < h; y++) {
561
0
            FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, h - 1 - y);
562
0
            for(x = 0; x < w; x++) {
563
0
              image->comps[0].data[index] = bits[x].red;
564
0
              image->comps[1].data[index] = bits[x].green;
565
0
              image->comps[2].data[index] = bits[x].blue;
566
0
              index++;
567
0
            }
568
0
          }
569
0
          break;
570
0
        case 4:
571
0
          index = 0;
572
0
          for(y = 0; y < h; y++) {
573
0
            FIRGBA16 *bits = (FIRGBA16*)FreeImage_GetScanLine(dib, h - 1 - y);
574
0
            for(x = 0; x < w; x++) {
575
0
              image->comps[0].data[index] = bits[x].red;
576
0
              image->comps[1].data[index] = bits[x].green;
577
0
              image->comps[2].data[index] = bits[x].blue;
578
0
              image->comps[3].data[index] = bits[x].alpha;
579
0
              index++;
580
0
            }
581
0
          }
582
0
          break;
583
0
      }
584
0
    }
585
586
0
    return image;
587
588
0
  } catch (const char *text) {
589
0
    if(image) opj_image_destroy(image);
590
0
    FreeImage_OutputMessageProc(format_id, text);
591
    return NULL;
592
0
  }
593
0
}