Initial commit.
[pdfium.git] / core / src / fxcodec / codec / fx_codec_jpx_opj.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4  \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 \r
7 #include "../../../include/fxcodec/fx_codec.h"\r
8 #include "codec_int.h"\r
9 #include "../fx_libopenjpeg/libopenjpeg20/openjpeg.h"\r
10 #include "../lcms2/include/fx_lcms2.h"\r
11 static void fx_error_callback(const char *msg, void *client_data)\r
12 {\r
13     (void)client_data;\r
14 }\r
15 static void fx_warning_callback(const char *msg, void *client_data)\r
16 {\r
17     (void)client_data;\r
18 }\r
19 static void fx_info_callback(const char *msg, void *client_data)\r
20 {\r
21     (void)client_data;\r
22 }\r
23 typedef struct {\r
24     const unsigned char* src_data;\r
25     int                                  src_size;\r
26     int                                  offset;\r
27 } decodeData;\r
28 static OPJ_SIZE_T opj_read_from_memory (void * p_buffer, OPJ_SIZE_T p_nb_bytes,  decodeData* srcData)\r
29 {\r
30     if(srcData == NULL || srcData->src_size == 0 || srcData->src_data == NULL || srcData->offset >= srcData->src_size) {\r
31         return -1;\r
32     }\r
33     OPJ_SIZE_T readlength = p_nb_bytes;\r
34     OPJ_SIZE_T bufferLength = (OPJ_SIZE_T)(srcData->src_size - srcData->offset);\r
35     if(bufferLength <= 0) {\r
36         return 0;\r
37     }\r
38     if(bufferLength <= p_nb_bytes) {\r
39         readlength = bufferLength;\r
40     }\r
41     memcpy(p_buffer, &(srcData->src_data[srcData->offset]), readlength);\r
42     srcData->offset += (int)readlength;\r
43     return readlength;\r
44 }\r
45 static OPJ_SIZE_T opj_write_from_memory (void * p_buffer, OPJ_SIZE_T p_nb_bytes, decodeData* srcData)\r
46 {\r
47     if(srcData == NULL || srcData->src_size == 0 || srcData->src_data == NULL || srcData->offset >= srcData->src_size) {\r
48         return -1;\r
49     }\r
50     OPJ_SIZE_T writeLength = p_nb_bytes;\r
51     OPJ_SIZE_T bufferLength = (OPJ_SIZE_T)(srcData->src_size - srcData->offset);\r
52     if(bufferLength <= p_nb_bytes) {\r
53         writeLength = bufferLength;\r
54     }\r
55     memcpy((void*&)(srcData->src_data[srcData->offset]), p_buffer, writeLength);\r
56     srcData->offset += (int)writeLength;\r
57     return writeLength;\r
58 }\r
59 static OPJ_OFF_T opj_skip_from_memory (OPJ_OFF_T p_nb_bytes, decodeData* srcData)\r
60 {\r
61     if(srcData == NULL || srcData->src_size == 0 || srcData->src_data == NULL || srcData->offset >= srcData->src_size) {\r
62         return -1;\r
63     }\r
64     OPJ_OFF_T postion = srcData->offset + p_nb_bytes;\r
65     if(postion < 0 ) {\r
66         postion = 0;\r
67     } else if (postion > srcData->src_size) {\r
68     }\r
69     srcData->offset = (int)postion;\r
70     return p_nb_bytes;\r
71 }\r
72 static OPJ_BOOL opj_seek_from_memory (OPJ_OFF_T p_nb_bytes, decodeData * srcData)\r
73 {\r
74     if(srcData == NULL || srcData->src_size == 0 || srcData->src_data == NULL || srcData->offset >= srcData->src_size) {\r
75         return -1;\r
76     }\r
77     srcData->offset = (int)p_nb_bytes;\r
78     if(srcData->offset < 0) {\r
79         srcData->offset = 0;\r
80     } else if(srcData->offset > srcData->src_size) {\r
81         srcData->offset = srcData->src_size;\r
82     }\r
83     return OPJ_TRUE;\r
84 }\r
85 opj_stream_t* fx_opj_stream_create_memory_stream (decodeData* data,     OPJ_SIZE_T p_size,      OPJ_BOOL p_is_read_stream)\r
86 {\r
87     opj_stream_t* l_stream = 00;\r
88     if (!data || ! data->src_data || data->src_size <= 0 ) {\r
89         return NULL;\r
90     }\r
91     l_stream = opj_stream_create(p_size, p_is_read_stream);\r
92     if (! l_stream) {\r
93         return NULL;\r
94     }\r
95     opj_stream_set_user_data_v3(l_stream, data, NULL);\r
96     opj_stream_set_user_data_length(l_stream, data->src_size);\r
97     opj_stream_set_read_function(l_stream, (opj_stream_read_fn) opj_read_from_memory);\r
98     opj_stream_set_write_function(l_stream, (opj_stream_write_fn) opj_write_from_memory);\r
99     opj_stream_set_skip_function(l_stream, (opj_stream_skip_fn) opj_skip_from_memory);\r
100     opj_stream_set_seek_function(l_stream, (opj_stream_seek_fn) opj_seek_from_memory);\r
101     return l_stream;\r
102 }\r
103 static void sycc_to_rgb(int offset, int upb, int y, int cb, int cr,\r
104                         int *out_r, int *out_g, int *out_b)\r
105 {\r
106     int r, g, b;\r
107     cb -= offset;\r
108     cr -= offset;\r
109     r = y + (int)(1.402 * (float)cr);\r
110     if(r < 0) {\r
111         r = 0;\r
112     } else if(r > upb) {\r
113         r = upb;\r
114     } *out_r = r;\r
115     g = y - (int)(0.344 * (float)cb + 0.714 * (float)cr);\r
116     if(g < 0) {\r
117         g = 0;\r
118     } else if(g > upb) {\r
119         g = upb;\r
120     } *out_g = g;\r
121     b = y + (int)(1.772 * (float)cb);\r
122     if(b < 0) {\r
123         b = 0;\r
124     } else if(b > upb) {\r
125         b = upb;\r
126     } *out_b = b;\r
127 }\r
128 static void sycc444_to_rgb(opj_image_t *img)\r
129 {\r
130     int *d0, *d1, *d2, *r, *g, *b;\r
131     const int *y, *cb, *cr;\r
132     int maxw, maxh, max, i, offset, upb;\r
133     i = (int)img->comps[0].prec;\r
134     offset = 1 << (i - 1);\r
135     upb = (1 << i) - 1;\r
136     maxw = (int)img->comps[0].w;\r
137     maxh = (int)img->comps[0].h;\r
138     max = maxw * maxh;\r
139     y = img->comps[0].data;\r
140     cb = img->comps[1].data;\r
141     cr = img->comps[2].data;\r
142     d0 = r = FX_Alloc(int, (size_t)max);\r
143     d1 = g = FX_Alloc(int, (size_t)max);\r
144     d2 = b = FX_Alloc(int, (size_t)max);\r
145     for(i = 0; i < max; ++i) {\r
146         sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);\r
147         ++y;\r
148         ++cb;\r
149         ++cr;\r
150         ++r;\r
151         ++g;\r
152         ++b;\r
153     }\r
154     FX_Free(img->comps[0].data);\r
155     img->comps[0].data = d0;\r
156     FX_Free(img->comps[1].data);\r
157     img->comps[1].data = d1;\r
158     FX_Free(img->comps[2].data);\r
159     img->comps[2].data = d2;\r
160 }\r
161 static void sycc422_to_rgb(opj_image_t *img)\r
162 {\r
163     int *d0, *d1, *d2, *r, *g, *b;\r
164     const int *y, *cb, *cr;\r
165     int maxw, maxh, max, offset, upb;\r
166     int i, j;\r
167     i = (int)img->comps[0].prec;\r
168     offset = 1 << (i - 1);\r
169     upb = (1 << i) - 1;\r
170     maxw = (int)img->comps[0].w;\r
171     maxh = (int)img->comps[0].h;\r
172     max = maxw * maxh;\r
173     y = img->comps[0].data;\r
174     cb = img->comps[1].data;\r
175     cr = img->comps[2].data;\r
176     d0 = r = FX_Alloc(int, (size_t)max);\r
177     d1 = g = FX_Alloc(int, (size_t)max);\r
178     d2 = b = FX_Alloc(int, (size_t)max);\r
179     for(i = 0; i < maxh; ++i) {\r
180         for(j = 0; j < maxw; j += 2) {\r
181             sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);\r
182             ++y;\r
183             ++r;\r
184             ++g;\r
185             ++b;\r
186             sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);\r
187             ++y;\r
188             ++r;\r
189             ++g;\r
190             ++b;\r
191             ++cb;\r
192             ++cr;\r
193         }\r
194     }\r
195     FX_Free(img->comps[0].data);\r
196     img->comps[0].data = d0;\r
197     FX_Free(img->comps[1].data);\r
198     img->comps[1].data = d1;\r
199     FX_Free(img->comps[2].data);\r
200     img->comps[2].data = d2;\r
201     img->comps[1].w = maxw;\r
202     img->comps[1].h = maxh;\r
203     img->comps[2].w = maxw;\r
204     img->comps[2].h = maxh;\r
205     img->comps[1].w = (OPJ_UINT32)maxw;\r
206     img->comps[1].h = (OPJ_UINT32)maxh;\r
207     img->comps[2].w = (OPJ_UINT32)maxw;\r
208     img->comps[2].h = (OPJ_UINT32)maxh;\r
209     img->comps[1].dx = img->comps[0].dx;\r
210     img->comps[2].dx = img->comps[0].dx;\r
211     img->comps[1].dy = img->comps[0].dy;\r
212     img->comps[2].dy = img->comps[0].dy;\r
213 }\r
214 static void sycc420_to_rgb(opj_image_t *img)\r
215 {\r
216     int *d0, *d1, *d2, *r, *g, *b, *nr, *ng, *nb;\r
217     const int *y, *cb, *cr, *ny;\r
218     int maxw, maxh, max, offset, upb;\r
219     int i, j;\r
220     i = (int)img->comps[0].prec;\r
221     offset = 1 << (i - 1);\r
222     upb = (1 << i) - 1;\r
223     maxw = (int)img->comps[0].w;\r
224     maxh = (int)img->comps[0].h;\r
225     max = maxw * maxh;\r
226     y = img->comps[0].data;\r
227     cb = img->comps[1].data;\r
228     cr = img->comps[2].data;\r
229     d0 = r = FX_Alloc(int, (size_t)max);\r
230     d1 = g = FX_Alloc(int, (size_t)max);\r
231     d2 = b = FX_Alloc(int, (size_t)max);\r
232     for(i = 0; i < maxh; i += 2) {\r
233         ny = y + maxw;\r
234         nr = r + maxw;\r
235         ng = g + maxw;\r
236         nb = b + maxw;\r
237         for(j = 0; j < maxw;  j += 2) {\r
238             sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);\r
239             ++y;\r
240             ++r;\r
241             ++g;\r
242             ++b;\r
243             sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);\r
244             ++y;\r
245             ++r;\r
246             ++g;\r
247             ++b;\r
248             sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb);\r
249             ++ny;\r
250             ++nr;\r
251             ++ng;\r
252             ++nb;\r
253             sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb);\r
254             ++ny;\r
255             ++nr;\r
256             ++ng;\r
257             ++nb;\r
258             ++cb;\r
259             ++cr;\r
260         }\r
261         y += maxw;\r
262         r += maxw;\r
263         g += maxw;\r
264         b += maxw;\r
265     }\r
266     FX_Free(img->comps[0].data);\r
267     img->comps[0].data = d0;\r
268     FX_Free(img->comps[1].data);\r
269     img->comps[1].data = d1;\r
270     FX_Free(img->comps[2].data);\r
271     img->comps[2].data = d2;\r
272     img->comps[1].w = maxw;\r
273     img->comps[1].h = maxh;\r
274     img->comps[2].w = maxw;\r
275     img->comps[2].h = maxh;\r
276     img->comps[1].w = (OPJ_UINT32)maxw;\r
277     img->comps[1].h = (OPJ_UINT32)maxh;\r
278     img->comps[2].w = (OPJ_UINT32)maxw;\r
279     img->comps[2].h = (OPJ_UINT32)maxh;\r
280     img->comps[1].dx = img->comps[0].dx;\r
281     img->comps[2].dx = img->comps[0].dx;\r
282     img->comps[1].dy = img->comps[0].dy;\r
283     img->comps[2].dy = img->comps[0].dy;\r
284 }\r
285 void color_sycc_to_rgb(opj_image_t *img)\r
286 {\r
287     if(img->numcomps < 3) {\r
288         img->color_space = OPJ_CLRSPC_GRAY;\r
289         return;\r
290     }\r
291     if((img->comps[0].dx == 1)\r
292             && (img->comps[1].dx == 2)\r
293             && (img->comps[2].dx == 2)\r
294             && (img->comps[0].dy == 1)\r
295             && (img->comps[1].dy == 2)\r
296             && (img->comps[2].dy == 2)) {\r
297         sycc420_to_rgb(img);\r
298     } else if((img->comps[0].dx == 1)\r
299               && (img->comps[1].dx == 2)\r
300               && (img->comps[2].dx == 2)\r
301               && (img->comps[0].dy == 1)\r
302               && (img->comps[1].dy == 1)\r
303               && (img->comps[2].dy == 1)) {\r
304         sycc422_to_rgb(img);\r
305     } else if((img->comps[0].dx == 1)\r
306               && (img->comps[1].dx == 1)\r
307               && (img->comps[2].dx == 1)\r
308               && (img->comps[0].dy == 1)\r
309               && (img->comps[1].dy == 1)\r
310               && (img->comps[2].dy == 1)) {\r
311         sycc444_to_rgb(img);\r
312     } else {\r
313         return;\r
314     }\r
315     img->color_space = OPJ_CLRSPC_SRGB;\r
316 }\r
317 void color_apply_icc_profile(opj_image_t *image)\r
318 {\r
319     cmsHPROFILE in_prof, out_prof;\r
320     cmsHTRANSFORM transform;\r
321     cmsColorSpaceSignature in_space, out_space;\r
322     cmsUInt32Number intent, in_type, out_type, nr_samples;\r
323     int *r, *g, *b;\r
324     int prec, i, max, max_w, max_h;\r
325     OPJ_COLOR_SPACE oldspace;\r
326     in_prof =\r
327         cmsOpenProfileFromMem(image->icc_profile_buf, image->icc_profile_len);\r
328     if(in_prof == NULL) {\r
329         return;\r
330     }\r
331     in_space = cmsGetPCS(in_prof);\r
332     out_space = cmsGetColorSpace(in_prof);\r
333     intent = cmsGetHeaderRenderingIntent(in_prof);\r
334     max_w = (int)image->comps[0].w;\r
335     max_h = (int)image->comps[0].h;\r
336     prec = (int)image->comps[0].prec;\r
337     oldspace = image->color_space;\r
338     if(out_space == cmsSigRgbData) {\r
339         if( prec <= 8 ) {\r
340             in_type = TYPE_RGB_8;\r
341             out_type = TYPE_RGB_8;\r
342         } else {\r
343             in_type = TYPE_RGB_16;\r
344             out_type = TYPE_RGB_16;\r
345         }\r
346         out_prof = cmsCreate_sRGBProfile();\r
347         image->color_space = OPJ_CLRSPC_SRGB;\r
348     } else if(out_space == cmsSigGrayData) {\r
349         if( prec <= 8 ) {\r
350             in_type = TYPE_GRAY_8;\r
351             out_type = TYPE_RGB_8;\r
352         } else {\r
353             in_type = TYPE_GRAY_16;\r
354             out_type = TYPE_RGB_16;\r
355         }\r
356         out_prof = cmsCreate_sRGBProfile();\r
357         image->color_space = OPJ_CLRSPC_SRGB;\r
358     } else if(out_space == cmsSigYCbCrData) {\r
359         in_type = TYPE_YCbCr_16;\r
360         out_type = TYPE_RGB_16;\r
361         out_prof = cmsCreate_sRGBProfile();\r
362         image->color_space = OPJ_CLRSPC_SRGB;\r
363     } else {\r
364         return;\r
365     }\r
366     transform = cmsCreateTransform(in_prof, in_type,\r
367                                    out_prof, out_type, intent, 0);\r
368     cmsCloseProfile(in_prof);\r
369     cmsCloseProfile(out_prof);\r
370     if(transform == NULL) {\r
371         image->color_space = oldspace;\r
372         return;\r
373     }\r
374     if(image->numcomps > 2) {\r
375         if( prec <= 8 ) {\r
376             unsigned char *inbuf, *outbuf, *in, *out;\r
377             max = max_w * max_h;\r
378             nr_samples = (cmsUInt32Number)max * 3 * (cmsUInt32Number)sizeof(unsigned char);\r
379             in = inbuf = FX_Alloc(unsigned char, nr_samples);\r
380             out = outbuf = FX_Alloc(unsigned char, nr_samples);\r
381             r = image->comps[0].data;\r
382             g = image->comps[1].data;\r
383             b = image->comps[2].data;\r
384             for(i = 0; i < max; ++i) {\r
385                 *in++ = (unsigned char) * r++;\r
386                 *in++ = (unsigned char) * g++;\r
387                 *in++ = (unsigned char) * b++;\r
388             }\r
389             cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max);\r
390             r = image->comps[0].data;\r
391             g = image->comps[1].data;\r
392             b = image->comps[2].data;\r
393             for(i = 0; i < max; ++i) {\r
394                 *r++ = (int) * out++;\r
395                 *g++ = (int) * out++;\r
396                 *b++ = (int) * out++;\r
397             }\r
398             FX_Free(inbuf);\r
399             FX_Free(outbuf);\r
400         } else {\r
401             unsigned short *inbuf, *outbuf, *in, *out;\r
402             max = max_w * max_h;\r
403             nr_samples = (cmsUInt32Number)max * 3 * (cmsUInt32Number)sizeof(unsigned short);\r
404             in = inbuf = FX_Alloc(unsigned short, nr_samples);\r
405             out = outbuf = FX_Alloc(unsigned short, nr_samples);\r
406             r = image->comps[0].data;\r
407             g = image->comps[1].data;\r
408             b = image->comps[2].data;\r
409             for(i = 0; i < max; ++i) {\r
410                 *in++ = (unsigned short) * r++;\r
411                 *in++ = (unsigned short) * g++;\r
412                 *in++ = (unsigned short) * b++;\r
413             }\r
414             cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max);\r
415             r = image->comps[0].data;\r
416             g = image->comps[1].data;\r
417             b = image->comps[2].data;\r
418             for(i = 0; i < max; ++i) {\r
419                 *r++ = (int) * out++;\r
420                 *g++ = (int) * out++;\r
421                 *b++ = (int) * out++;\r
422             }\r
423             FX_Free(inbuf);\r
424             FX_Free(outbuf);\r
425         }\r
426     } else {\r
427         unsigned char *in, *inbuf, *out, *outbuf;\r
428         max = max_w * max_h;\r
429         nr_samples = (cmsUInt32Number)max * 3 * sizeof(unsigned char);\r
430         in = inbuf = FX_Alloc(unsigned char, nr_samples);\r
431         out = outbuf = FX_Alloc(unsigned char, nr_samples);\r
432         image->comps = (opj_image_comp_t*)\r
433                        realloc(image->comps, (image->numcomps + 2) * sizeof(opj_image_comp_t));\r
434         if(image->numcomps == 2) {\r
435             image->comps[3] = image->comps[1];\r
436         }\r
437         image->comps[1] = image->comps[0];\r
438         image->comps[2] = image->comps[0];\r
439         image->comps[1].data = FX_Alloc(int, (size_t)max);\r
440         FXSYS_memset8(image->comps[1].data, 0, sizeof(int) * (size_t)max);\r
441         image->comps[2].data = FX_Alloc(int, (size_t)max);\r
442         FXSYS_memset8(image->comps[2].data, 0, sizeof(int) * (size_t)max);\r
443         image->numcomps += 2;\r
444         r = image->comps[0].data;\r
445         for(i = 0; i < max; ++i) {\r
446             *in++ = (unsigned char) * r++;\r
447         }\r
448         cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max);\r
449         r = image->comps[0].data;\r
450         g = image->comps[1].data;\r
451         b = image->comps[2].data;\r
452         for(i = 0; i < max; ++i) {\r
453             *r++ = (int) * out++;\r
454             *g++ = (int) * out++;\r
455             *b++ = (int) * out++;\r
456         }\r
457         FX_Free(inbuf);\r
458         FX_Free(outbuf);\r
459     }\r
460     cmsDeleteTransform(transform);\r
461 }\r
462 void color_apply_conversion(opj_image_t *image)\r
463 {\r
464     int *row;\r
465     int enumcs, numcomps;\r
466     numcomps = image->numcomps;\r
467     if(numcomps < 3) {\r
468         return;\r
469     }\r
470     row = (int*)image->icc_profile_buf;\r
471     enumcs = row[0];\r
472     if(enumcs == 14) {\r
473         int *L, *a, *b, *red, *green, *blue, *src0, *src1, *src2;\r
474         double rl, ol, ra, oa, rb, ob, prec0, prec1, prec2;\r
475         double minL, maxL, mina, maxa, minb, maxb;\r
476         unsigned int default_type, il;\r
477         unsigned int i, max, illu;\r
478         cmsHPROFILE in, out;\r
479         cmsHTRANSFORM transform;\r
480         cmsUInt16Number RGB[3];\r
481         cmsCIELab Lab;\r
482         illu = 0;\r
483         il = 0;\r
484         in = cmsCreateLab4Profile(NULL);\r
485         out = cmsCreate_sRGBProfile();\r
486         transform =\r
487             cmsCreateTransform(in, TYPE_Lab_DBL, out, TYPE_RGB_16,\r
488                                INTENT_PERCEPTUAL, 0);\r
489         cmsCloseProfile(in);\r
490         cmsCloseProfile(out);\r
491         if(transform == NULL) {\r
492             return;\r
493         }\r
494         prec0 = (double)image->comps[0].prec;\r
495         prec1 = (double)image->comps[1].prec;\r
496         prec2 = (double)image->comps[2].prec;\r
497         default_type = row[1];\r
498         if(default_type == 0x44454600) {\r
499             rl = 100;\r
500             ra = 170;\r
501             rb = 200;\r
502             ol = 0;\r
503             oa = pow(2, prec1 - 1);\r
504             ob = pow(2, prec2 - 2)  + pow(2, prec2 - 3);\r
505         } else {\r
506             rl = row[2];\r
507             ra = row[4];\r
508             rb = row[6];\r
509             ol = row[3];\r
510             oa = row[5];\r
511             ob = row[7];\r
512         }\r
513         L = src0 = image->comps[0].data;\r
514         a = src1 = image->comps[1].data;\r
515         b = src2 = image->comps[2].data;\r
516         max = image->comps[0].w * image->comps[0].h;\r
517         red = FX_Alloc(int, max);\r
518         image->comps[0].data = red;\r
519         green = FX_Alloc(int, max);\r
520         image->comps[1].data = green;\r
521         blue = FX_Alloc(int, max);\r
522         image->comps[2].data = blue;\r
523         minL = -(rl * ol) / (pow(2, prec0) - 1);\r
524         maxL = minL + rl;\r
525         mina = -(ra * oa) / (pow(2, prec1) - 1);\r
526         maxa = mina + ra;\r
527         minb = -(rb * ob) / (pow(2, prec2) - 1);\r
528         maxb = minb + rb;\r
529         for(i = 0; i < max; ++i) {\r
530             Lab.L = minL + (double)(*L) * (maxL - minL) / (pow(2, prec0) - 1);\r
531             ++L;\r
532             Lab.a = mina + (double)(*a) * (maxa - mina) / (pow(2, prec1) - 1);\r
533             ++a;\r
534             Lab.b = minb + (double)(*b) * (maxb - minb) / (pow(2, prec2) - 1);\r
535             ++b;\r
536             cmsDoTransform(transform, &Lab, RGB, 1);\r
537             *red++ = RGB[0];\r
538             *green++ = RGB[1];\r
539             *blue++ = RGB[2];\r
540         }\r
541         cmsDeleteTransform(transform);\r
542         FX_Free(src0);\r
543         FX_Free(src1);\r
544         FX_Free(src2);\r
545         image->color_space = OPJ_CLRSPC_SRGB;\r
546         image->comps[0].prec = 16;\r
547         image->comps[1].prec = 16;\r
548         image->comps[2].prec = 16;\r
549         return;\r
550     }\r
551 }\r
552 class CJPX_Decoder : public CFX_Object\r
553 {\r
554 public:\r
555     CJPX_Decoder();\r
556     ~CJPX_Decoder();\r
557     FX_BOOL     Init(const unsigned char* src_data, int src_size);\r
558     void        GetInfo(FX_DWORD& width, FX_DWORD& height, FX_DWORD& codestream_nComps, FX_DWORD& output_nComps);\r
559     FX_BOOL     Decode(FX_LPBYTE dest_buf, int pitch, FX_BOOL bTranslateColor, FX_LPBYTE offsets);\r
560     FX_LPCBYTE m_SrcData;\r
561     int m_SrcSize;\r
562     opj_image_t *image;\r
563     opj_codec_t* l_codec;\r
564     opj_stream_t *l_stream;\r
565     FX_BOOL m_useColorSpace;\r
566 };\r
567 CJPX_Decoder::CJPX_Decoder(): image(NULL), l_codec(NULL), l_stream(NULL), m_useColorSpace(FALSE)\r
568 {\r
569 }\r
570 CJPX_Decoder::~CJPX_Decoder()\r
571 {\r
572     if(l_codec) {\r
573         opj_destroy_codec(l_codec);\r
574     }\r
575     if(l_stream) {\r
576         opj_stream_destroy(l_stream);\r
577     }\r
578     if(image) {\r
579         opj_image_destroy(image);\r
580     }\r
581 }\r
582 FX_BOOL CJPX_Decoder::Init(const unsigned char* src_data, int src_size)\r
583 {\r
584     opj_dparameters_t parameters;\r
585     try {\r
586         image = NULL;\r
587         m_SrcData = src_data;\r
588         m_SrcSize = src_size;\r
589         decodeData srcData;\r
590         srcData.offset  = 0;\r
591         srcData.src_size = src_size;\r
592         srcData.src_data = src_data;\r
593         l_stream = fx_opj_stream_create_memory_stream(&srcData, OPJ_J2K_STREAM_CHUNK_SIZE, 1);\r
594         if (l_stream == NULL) {\r
595             return FALSE;\r
596         }\r
597         opj_set_default_decoder_parameters(&parameters);\r
598         parameters.decod_format = 0;\r
599         parameters.cod_format = 3;\r
600         if(FXSYS_memcmp32(m_SrcData, "\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a", 12) == 0) {\r
601             l_codec = opj_create_decompress(OPJ_CODEC_JP2);\r
602             parameters.decod_format = 1;\r
603         } else {\r
604             l_codec = opj_create_decompress(OPJ_CODEC_J2K);\r
605         }\r
606         if(!l_codec) {\r
607             return FALSE;\r
608         }\r
609         opj_set_info_handler(l_codec, fx_info_callback, 00);\r
610         opj_set_warning_handler(l_codec, fx_warning_callback, 00);\r
611         opj_set_error_handler(l_codec, fx_error_callback, 00);\r
612         if ( !opj_setup_decoder(l_codec, &parameters) ) {\r
613             return FALSE;\r
614         }\r
615         if(! opj_read_header(l_stream, l_codec, &image)) {\r
616             image = NULL;\r
617             return FALSE;\r
618         }\r
619         if(this->m_useColorSpace) {\r
620             image->useColorSpace = 1;\r
621         } else {\r
622             image->useColorSpace = 0;\r
623         }\r
624         if (!parameters.nb_tile_to_decode) {\r
625             if (!opj_set_decode_area(l_codec, image, parameters.DA_x0,\r
626                                      parameters.DA_y0, parameters.DA_x1, parameters.DA_y1)) {\r
627                 opj_image_destroy(image);\r
628                 image = NULL;\r
629                 return FALSE;\r
630             }\r
631             if (!(opj_decode(l_codec, l_stream, image) && opj_end_decompress(l_codec,   l_stream))) {\r
632                 opj_image_destroy(image);\r
633                 image = NULL;\r
634                 return FALSE;\r
635             }\r
636         } else {\r
637             if (!opj_get_decoded_tile(l_codec, l_stream, image, parameters.tile_index)) {\r
638                 return FALSE;\r
639             }\r
640         }\r
641         opj_stream_destroy(l_stream);\r
642         l_stream = NULL;\r
643         if( image->color_space != OPJ_CLRSPC_SYCC\r
644                 && image->numcomps == 3 && image->comps[0].dx == image->comps[0].dy\r
645                 && image->comps[1].dx != 1 ) {\r
646             image->color_space = OPJ_CLRSPC_SYCC;\r
647         } else if (image->numcomps <= 2) {\r
648             image->color_space = OPJ_CLRSPC_GRAY;\r
649         }\r
650         if(image->color_space == OPJ_CLRSPC_SYCC) {\r
651             color_sycc_to_rgb(image);\r
652         }\r
653         if(image->icc_profile_buf && !image->useColorSpace) {\r
654             FX_Free(image->icc_profile_buf);\r
655             image->icc_profile_buf = NULL;\r
656             image->icc_profile_len = 0;\r
657         }\r
658         if(!image) {\r
659             return FALSE;\r
660         }\r
661     } catch (...) {\r
662         return FALSE;\r
663     }\r
664     return TRUE;\r
665 }\r
666 void CJPX_Decoder::GetInfo(FX_DWORD& width, FX_DWORD& height, FX_DWORD& codestream_nComps, FX_DWORD& output_nComps)\r
667 {\r
668     width = (FX_DWORD)image->x1;\r
669     height = (FX_DWORD)image->y1;\r
670     output_nComps = codestream_nComps = (FX_DWORD)image->numcomps;\r
671 }\r
672 FX_BOOL CJPX_Decoder::Decode(FX_LPBYTE dest_buf, int pitch, FX_BOOL bTranslateColor, FX_LPBYTE offsets)\r
673 {\r
674     FX_BYTE** channel_bufs;\r
675     int* adjust_comps;\r
676     int i, wid, hei, row, col, channel, src;\r
677     FX_BOOL flag;\r
678     FX_LPBYTE pChannel, pScanline, pPixel;\r
679     try {\r
680         if(image->comps[0].w != image->x1 || image->comps[0].h != image->y1) {\r
681             return FALSE;\r
682         }\r
683         if(pitch < (int)(image->comps[0].w * 8 * image->numcomps + 31) >> 5 << 2) {\r
684             return FALSE;\r
685         }\r
686         FXSYS_memset8(dest_buf, 0xff, image->y1 * pitch);\r
687         channel_bufs = FX_Alloc(FX_BYTE*, image->numcomps);\r
688         if (channel_bufs == NULL) {\r
689             return FALSE;\r
690         }\r
691         adjust_comps = FX_Alloc(int, image->numcomps);\r
692         if (adjust_comps == NULL) {\r
693             FX_Free(channel_bufs);\r
694             return FALSE;\r
695         }\r
696         flag = TRUE;\r
697         for (i = 0; i < (int)image->numcomps; i ++) {\r
698             channel_bufs[i] = dest_buf + offsets[i];\r
699             adjust_comps[i] = image->comps[i].prec - 8;\r
700             if(i > 0) {\r
701                 if(image->comps[i].dx != image->comps[i - 1].dx\r
702                         || image->comps[i].dy != image->comps[i - 1].dy\r
703                         || image->comps[i].prec != image->comps[i - 1].prec) {\r
704                     flag = FALSE;\r
705                     goto failed;\r
706                 }\r
707             }\r
708         }\r
709         wid = image->comps[0].w;\r
710         hei = image->comps[0].h;\r
711         for (channel = 0; channel < (int)image->numcomps; channel++) {\r
712             pChannel = channel_bufs[channel];\r
713             if(adjust_comps[channel] < 0) {\r
714                 for(row = 0; row < hei; row++) {\r
715                     pScanline = pChannel + row * pitch;\r
716                     for (col = 0; col < wid; col++) {\r
717                         pPixel = pScanline + col * image->numcomps;\r
718                         src = image->comps[channel].data[row * wid + col];\r
719                         src += image->comps[channel].sgnd ? 1 << (image->comps[channel].prec - 1) : 0;\r
720                         if (adjust_comps[channel] > 0) {\r
721                             *pPixel = 0;\r
722                         } else {\r
723                             *pPixel = (FX_BYTE)(src << -adjust_comps[channel]);\r
724                         }\r
725                     }\r
726                 }\r
727             } else {\r
728                 for(row = 0; row < hei; row++) {\r
729                     pScanline = pChannel + row * pitch;\r
730                     for (col = 0; col < wid; col++) {\r
731                         pPixel = pScanline + col * image->numcomps;\r
732                                                 if (!image->comps[channel].data) continue;\r
733                         src = image->comps[channel].data[row * wid + col];\r
734                         src += image->comps[channel].sgnd ? 1 << (image->comps[channel].prec - 1) : 0;\r
735                         if (adjust_comps[channel] - 1 < 0) {\r
736                             *pPixel = (FX_BYTE)((src >> adjust_comps[channel]));\r
737                         } else {\r
738                             int tmpPixel = (src >> adjust_comps[channel]) + ((src >> (adjust_comps[channel] - 1)) % 2);\r
739                             if (tmpPixel > 255) {\r
740                                 tmpPixel = 255;\r
741                             } else if (tmpPixel < 0) {\r
742                                 tmpPixel = 0;\r
743                             }\r
744                             *pPixel = (FX_BYTE)tmpPixel;\r
745                         }\r
746                     }\r
747                 }\r
748             }\r
749         }\r
750     } catch (...) {\r
751         if (channel_bufs) {\r
752             FX_Free(channel_bufs);\r
753         }\r
754         FX_Free(adjust_comps);\r
755         return FALSE;\r
756     }\r
757     FX_Free(channel_bufs);\r
758     FX_Free(adjust_comps);\r
759     return TRUE;\r
760 failed:\r
761     FX_Free(channel_bufs);\r
762     FX_Free(adjust_comps);\r
763     return FALSE;\r
764 }\r
765 void initialize_transition_table();\r
766 void initialize_significance_luts();\r
767 void initialize_sign_lut();\r
768 CCodec_JpxModule::CCodec_JpxModule()\r
769 {\r
770 }\r
771 void* CCodec_JpxModule::CreateDecoder(FX_LPCBYTE src_buf, FX_DWORD src_size , FX_BOOL useColorSpace)\r
772 {\r
773     CJPX_Decoder* pDecoder = FX_NEW CJPX_Decoder;\r
774     if (pDecoder == NULL) {\r
775         return NULL;\r
776     }\r
777     pDecoder->m_useColorSpace = useColorSpace;\r
778     if (!pDecoder->Init(src_buf, src_size)) {\r
779         delete pDecoder;\r
780         return NULL;\r
781     }\r
782     return pDecoder;\r
783 }\r
784 void CCodec_JpxModule::GetImageInfo(FX_LPVOID ctx, FX_DWORD& width, FX_DWORD& height,\r
785                                     FX_DWORD& codestream_nComps, FX_DWORD& output_nComps)\r
786 {\r
787     CJPX_Decoder* pDecoder = (CJPX_Decoder*)ctx;\r
788     pDecoder->GetInfo(width, height, codestream_nComps, output_nComps);\r
789 }\r
790 FX_BOOL CCodec_JpxModule::Decode(void* ctx, FX_LPBYTE dest_data, int pitch, FX_BOOL bTranslateColor, FX_LPBYTE offsets)\r
791 {\r
792     CJPX_Decoder* pDecoder = (CJPX_Decoder*)ctx;\r
793     return pDecoder->Decode(dest_data, pitch, bTranslateColor, offsets);\r
794 }\r
795 void CCodec_JpxModule::DestroyDecoder(void* ctx)\r
796 {\r
797     CJPX_Decoder* pDecoder = (CJPX_Decoder*)ctx;\r
798     delete pDecoder;\r
799 }\r