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