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