/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 | } |