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.
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
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"
15 static void fx_error_callback(const char *msg, void *client_data)
19 static void fx_warning_callback(const char *msg, void *client_data)
23 static void fx_info_callback(const char *msg, void *client_data)
27 OPJ_SIZE_T opj_read_from_memory(void* p_buffer, OPJ_SIZE_T nb_bytes, void* p_user_data)
29 DecodeData* srcData = static_cast<DecodeData*>(p_user_data);
30 if (!srcData || !srcData->src_data || srcData->src_size == 0) {
33 // Reads at EOF return an error code.
34 if (srcData->offset >= srcData->src_size) {
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;
43 OPJ_SIZE_T opj_write_from_memory(void* p_buffer, OPJ_SIZE_T nb_bytes, void* p_user_data)
45 DecodeData* srcData = static_cast<DecodeData*>(p_user_data);
46 if (!srcData || !srcData->src_data || srcData->src_size == 0) {
49 // Writes at EOF return an error code.
50 if (srcData->offset >= srcData->src_size) {
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;
59 OPJ_OFF_T opj_skip_from_memory(OPJ_OFF_T nb_bytes, void* p_user_data)
61 DecodeData* srcData = static_cast<DecodeData*>(p_user_data);
62 if (!srcData || !srcData->src_data || srcData->src_size == 0) {
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.
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;
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
85 srcData->offset = std::min(srcData->offset + checkedNbBytes, srcData->src_size);
89 OPJ_BOOL opj_seek_from_memory(OPJ_OFF_T nb_bytes, void* p_user_data)
91 DecodeData* srcData = static_cast<DecodeData*>(p_user_data);
92 if (!srcData || !srcData->src_data || srcData->src_size == 0) {
95 // Offsets are signed and may indicate a negative position, which would
96 // be before the start of the file. Do not support this.
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;
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);
114 opj_stream_t* fx_opj_stream_create_memory_stream (DecodeData* data, OPJ_SIZE_T p_size, OPJ_BOOL p_is_read_stream)
116 opj_stream_t* l_stream = 00;
117 if (!data || ! data->src_data || data->src_size <= 0 ) {
120 l_stream = opj_stream_create(p_size, p_is_read_stream);
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);
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)
138 r = y + (int)(1.402 * (float)cr);
144 g = y - (int)(0.344 * (float)cb + 0.714 * (float)cr);
150 b = y + (int)(1.772 * (float)cb);
157 static void sycc444_to_rgb(opj_image_t *img)
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);
165 maxw = (int)img->comps[0].w;
166 maxh = (int)img->comps[0].h;
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);
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;
190 static void sycc422_to_rgb(opj_image_t *img)
192 int *d0, *d1, *d2, *r, *g, *b;
193 const int *y, *cb, *cr;
194 int maxw, maxh, max, offset, upb;
196 i = (int)img->comps[0].prec;
197 offset = 1 << (i - 1);
199 maxw = (int)img->comps[0].w;
200 maxh = (int)img->comps[0].h;
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)
210 for (j = 0; (OPJ_UINT32)j < (maxw & ~(OPJ_UINT32)1); j += 2)
212 sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
214 sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
215 ++y; ++r; ++g; ++b; ++cb; ++cr;
219 sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
220 ++y; ++r; ++g; ++b; ++cb; ++cr;
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;
242 static void sycc420_to_rgb(opj_image_t *img)
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;
248 i = (int)img->comps[0].prec;
249 offset = 1 << (i - 1);
251 maxw = (int)img->comps[0].w;
252 maxh = (int)img->comps[0].h;
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)
266 for (j = 0; (OPJ_UINT32)j < (maxw & ~(OPJ_UINT32)1); j += 2)
268 sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
270 sycc_to_rgb(offset, upb, *y, *cb, *cr, 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;
279 sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
281 sycc_to_rgb(offset, upb, *ny, *cb, *cr, nr, ng, nb);
282 ++ny; ++nr; ++ng; ++nb; ++cb; ++cr;
284 y += maxw; r += maxw; g += maxw; b += maxw;
288 for (j = 0; (OPJ_UINT32)j < (maxw & ~(OPJ_UINT32)1); j += 2)
290 sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
292 sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
293 ++y; ++r; ++g; ++b; ++cb; ++cr;
297 sycc_to_rgb(offset, upb, *y, *cb, *cr, r, g, b);
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;
320 void color_sycc_to_rgb(opj_image_t *img)
322 if(img->numcomps < 3) {
323 img->color_space = OPJ_CLRSPC_GRAY;
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)) {
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)) {
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)) {
350 img->color_space = OPJ_CLRSPC_SRGB;
352 void color_apply_icc_profile(opj_image_t *image)
354 cmsHPROFILE in_prof, out_prof;
355 cmsHTRANSFORM transform;
356 cmsColorSpaceSignature in_space, out_space;
357 cmsUInt32Number intent, in_type, out_type, nr_samples;
359 int prec, i, max, max_w, max_h;
360 OPJ_COLOR_SPACE oldspace;
362 cmsOpenProfileFromMem(image->icc_profile_buf, image->icc_profile_len);
363 if(in_prof == NULL) {
366 in_space = cmsGetPCS(in_prof);
367 out_space = cmsGetColorSpace(in_prof);
368 intent = cmsGetHeaderRenderingIntent(in_prof);
369 max_w = (int)image->comps[0].w;
370 max_h = (int)image->comps[0].h;
371 prec = (int)image->comps[0].prec;
372 oldspace = image->color_space;
373 if(out_space == cmsSigRgbData) {
375 in_type = TYPE_RGB_8;
376 out_type = TYPE_RGB_8;
378 in_type = TYPE_RGB_16;
379 out_type = TYPE_RGB_16;
381 out_prof = cmsCreate_sRGBProfile();
382 image->color_space = OPJ_CLRSPC_SRGB;
383 } else if(out_space == cmsSigGrayData) {
385 in_type = TYPE_GRAY_8;
386 out_type = TYPE_RGB_8;
388 in_type = TYPE_GRAY_16;
389 out_type = TYPE_RGB_16;
391 out_prof = cmsCreate_sRGBProfile();
392 image->color_space = OPJ_CLRSPC_SRGB;
393 } else if(out_space == cmsSigYCbCrData) {
394 in_type = TYPE_YCbCr_16;
395 out_type = TYPE_RGB_16;
396 out_prof = cmsCreate_sRGBProfile();
397 image->color_space = OPJ_CLRSPC_SRGB;
401 transform = cmsCreateTransform(in_prof, in_type,
402 out_prof, out_type, intent, 0);
403 cmsCloseProfile(in_prof);
404 cmsCloseProfile(out_prof);
405 if(transform == NULL) {
406 image->color_space = oldspace;
409 if(image->numcomps > 2) {
411 unsigned char *inbuf, *outbuf, *in, *out;
413 nr_samples = (cmsUInt32Number)max * 3 * (cmsUInt32Number)sizeof(unsigned char);
414 in = inbuf = FX_Alloc(unsigned char, nr_samples);
415 out = outbuf = FX_Alloc(unsigned char, nr_samples);
416 r = image->comps[0].data;
417 g = image->comps[1].data;
418 b = image->comps[2].data;
419 for(i = 0; i < max; ++i) {
420 *in++ = (unsigned char) * r++;
421 *in++ = (unsigned char) * g++;
422 *in++ = (unsigned char) * b++;
424 cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max);
425 r = image->comps[0].data;
426 g = image->comps[1].data;
427 b = image->comps[2].data;
428 for(i = 0; i < max; ++i) {
429 *r++ = (int) * out++;
430 *g++ = (int) * out++;
431 *b++ = (int) * out++;
436 unsigned short *inbuf, *outbuf, *in, *out;
438 nr_samples = (cmsUInt32Number)max * 3 * (cmsUInt32Number)sizeof(unsigned short);
439 in = inbuf = FX_Alloc(unsigned short, nr_samples);
440 out = outbuf = FX_Alloc(unsigned short, nr_samples);
441 r = image->comps[0].data;
442 g = image->comps[1].data;
443 b = image->comps[2].data;
444 for(i = 0; i < max; ++i) {
445 *in++ = (unsigned short) * r++;
446 *in++ = (unsigned short) * g++;
447 *in++ = (unsigned short) * b++;
449 cmsDoTransform(transform, inbuf, outbuf, (cmsUInt32Number)max);
450 r = image->comps[0].data;
451 g = image->comps[1].data;
452 b = image->comps[2].data;
453 for(i = 0; i < max; ++i) {
454 *r++ = (int) * out++;
455 *g++ = (int) * out++;
456 *b++ = (int) * out++;
462 unsigned char *in, *inbuf, *out, *outbuf;
464 nr_samples = (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];
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_memset8(image->comps[1].data, 0, sizeof(int) * (size_t)max);
476 image->comps[2].data = FX_Alloc(int, (size_t)max);
477 FXSYS_memset8(image->comps[2].data, 0, sizeof(int) * (size_t)max);
478 image->numcomps += 2;
479 r = image->comps[0].data;
480 for(i = 0; i < max; ++i) {
481 *in++ = (unsigned char) * r++;
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(i = 0; i < max; ++i) {
488 *r++ = (int) * out++;
489 *g++ = (int) * out++;
490 *b++ = (int) * out++;
495 cmsDeleteTransform(transform);
497 void color_apply_conversion(opj_image_t *image)
500 int enumcs, numcomps;
501 numcomps = image->numcomps;
505 row = (int*)image->icc_profile_buf;
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, il;
512 unsigned int i, max, illu;
514 cmsHTRANSFORM transform;
515 cmsUInt16Number RGB[3];
519 in = cmsCreateLab4Profile(NULL);
520 out = cmsCreate_sRGBProfile();
522 cmsCreateTransform(in, TYPE_Lab_DBL, out, TYPE_RGB_16,
523 INTENT_PERCEPTUAL, 0);
525 cmsCloseProfile(out);
526 if(transform == NULL) {
529 prec0 = (double)image->comps[0].prec;
530 prec1 = (double)image->comps[1].prec;
531 prec2 = (double)image->comps[2].prec;
532 default_type = row[1];
533 if(default_type == 0x44454600) {
538 oa = pow(2, prec1 - 1);
539 ob = pow(2, prec2 - 2) + pow(2, prec2 - 3);
548 L = src0 = image->comps[0].data;
549 a = src1 = image->comps[1].data;
550 b = src2 = image->comps[2].data;
551 max = image->comps[0].w * image->comps[0].h;
552 red = FX_Alloc(int, max);
553 image->comps[0].data = red;
554 green = FX_Alloc(int, max);
555 image->comps[1].data = green;
556 blue = FX_Alloc(int, max);
557 image->comps[2].data = blue;
558 minL = -(rl * ol) / (pow(2, prec0) - 1);
560 mina = -(ra * oa) / (pow(2, prec1) - 1);
562 minb = -(rb * ob) / (pow(2, prec2) - 1);
564 for(i = 0; i < max; ++i) {
565 Lab.L = minL + (double)(*L) * (maxL - minL) / (pow(2, prec0) - 1);
567 Lab.a = mina + (double)(*a) * (maxa - mina) / (pow(2, prec1) - 1);
569 Lab.b = minb + (double)(*b) * (maxb - minb) / (pow(2, prec2) - 1);
571 cmsDoTransform(transform, &Lab, RGB, 1);
576 cmsDeleteTransform(transform);
580 image->color_space = OPJ_CLRSPC_SRGB;
581 image->comps[0].prec = 16;
582 image->comps[1].prec = 16;
583 image->comps[2].prec = 16;
592 FX_BOOL Init(const unsigned char* src_data, int src_size);
593 void GetInfo(FX_DWORD& width, FX_DWORD& height, FX_DWORD& codestream_nComps, FX_DWORD& output_nComps);
594 FX_BOOL Decode(FX_LPBYTE dest_buf, int pitch, FX_BOOL bTranslateColor, FX_LPBYTE offsets);
595 FX_LPCBYTE m_SrcData;
598 opj_codec_t* l_codec;
599 opj_stream_t *l_stream;
600 FX_BOOL m_useColorSpace;
602 CJPX_Decoder::CJPX_Decoder(): image(NULL), l_codec(NULL), l_stream(NULL), m_useColorSpace(FALSE)
605 CJPX_Decoder::~CJPX_Decoder()
608 opj_destroy_codec(l_codec);
611 opj_stream_destroy(l_stream);
614 opj_image_destroy(image);
617 FX_BOOL CJPX_Decoder::Init(const unsigned char* src_data, int src_size)
619 static const unsigned char szJP2Header[] = { 0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a };
620 if (!src_data || src_size < sizeof(szJP2Header)) {
624 m_SrcData = src_data;
625 m_SrcSize = src_size;
626 DecodeData srcData(const_cast<unsigned char*>(src_data), src_size);
627 l_stream = fx_opj_stream_create_memory_stream(&srcData, OPJ_J2K_STREAM_CHUNK_SIZE, 1);
628 if (l_stream == NULL) {
631 opj_dparameters_t parameters;
632 opj_set_default_decoder_parameters(¶meters);
633 parameters.decod_format = 0;
634 parameters.cod_format = 3;
635 if(FXSYS_memcmp32(m_SrcData, szJP2Header, sizeof(szJP2Header)) == 0) {
636 l_codec = opj_create_decompress(OPJ_CODEC_JP2);
637 parameters.decod_format = 1;
639 l_codec = opj_create_decompress(OPJ_CODEC_J2K);
644 opj_set_info_handler(l_codec, fx_info_callback, 00);
645 opj_set_warning_handler(l_codec, fx_warning_callback, 00);
646 opj_set_error_handler(l_codec, fx_error_callback, 00);
647 if ( !opj_setup_decoder(l_codec, ¶meters) ) {
650 if(! opj_read_header(l_stream, l_codec, &image)) {
655 if(this->m_useColorSpace) {
656 image->useColorSpace = 1;
658 image->useColorSpace = 0;
661 if (!parameters.nb_tile_to_decode) {
662 if (!opj_set_decode_area(l_codec, image, parameters.DA_x0,
663 parameters.DA_y0, parameters.DA_x1, parameters.DA_y1)) {
664 opj_image_destroy(image);
668 if (!(opj_decode(l_codec, l_stream, image) && opj_end_decompress(l_codec, l_stream))) {
669 opj_image_destroy(image);
674 if (!opj_get_decoded_tile(l_codec, l_stream, image, parameters.tile_index)) {
678 opj_stream_destroy(l_stream);
680 if( image->color_space != OPJ_CLRSPC_SYCC
681 && image->numcomps == 3 && image->comps[0].dx == image->comps[0].dy
682 && image->comps[1].dx != 1 ) {
683 image->color_space = OPJ_CLRSPC_SYCC;
684 } else if (image->numcomps <= 2) {
685 image->color_space = OPJ_CLRSPC_GRAY;
687 if(image->color_space == OPJ_CLRSPC_SYCC) {
688 color_sycc_to_rgb(image);
690 //if(image->icc_profile_buf && !image->useColorSpace) {
691 if(image->icc_profile_buf) {
692 FX_Free(image->icc_profile_buf);
693 image->icc_profile_buf = NULL;
694 image->icc_profile_len = 0;
701 void CJPX_Decoder::GetInfo(FX_DWORD& width, FX_DWORD& height, FX_DWORD& codestream_nComps, FX_DWORD& output_nComps)
703 width = (FX_DWORD)image->x1;
704 height = (FX_DWORD)image->y1;
705 output_nComps = codestream_nComps = (FX_DWORD)image->numcomps;
707 FX_BOOL CJPX_Decoder::Decode(FX_LPBYTE dest_buf, int pitch, FX_BOOL bTranslateColor, FX_LPBYTE offsets)
709 FX_BYTE** channel_bufs;
711 int i, wid, hei, row, col, channel, src;
713 FX_LPBYTE pChannel, pScanline, pPixel;
715 if(image->comps[0].w != image->x1 || image->comps[0].h != image->y1) {
718 if(pitch < (int)(image->comps[0].w * 8 * image->numcomps + 31) >> 5 << 2) {
721 FXSYS_memset8(dest_buf, 0xff, image->y1 * pitch);
722 channel_bufs = FX_Alloc(FX_BYTE*, image->numcomps);
723 if (channel_bufs == NULL) {
726 adjust_comps = FX_Alloc(int, image->numcomps);
727 if (adjust_comps == NULL) {
728 FX_Free(channel_bufs);
732 for (i = 0; i < (int)image->numcomps; i ++) {
733 channel_bufs[i] = dest_buf + offsets[i];
734 adjust_comps[i] = image->comps[i].prec - 8;
736 if(image->comps[i].dx != image->comps[i - 1].dx
737 || image->comps[i].dy != image->comps[i - 1].dy
738 || image->comps[i].prec != image->comps[i - 1].prec) {
744 wid = image->comps[0].w;
745 hei = image->comps[0].h;
746 for (channel = 0; channel < (int)image->numcomps; channel++) {
747 pChannel = channel_bufs[channel];
748 if(adjust_comps[channel] < 0) {
749 for(row = 0; row < hei; row++) {
750 pScanline = pChannel + row * pitch;
751 for (col = 0; col < wid; col++) {
752 pPixel = pScanline + col * image->numcomps;
753 src = image->comps[channel].data[row * wid + col];
754 src += image->comps[channel].sgnd ? 1 << (image->comps[channel].prec - 1) : 0;
755 if (adjust_comps[channel] > 0) {
758 *pPixel = (FX_BYTE)(src << -adjust_comps[channel]);
763 for(row = 0; row < hei; row++) {
764 pScanline = pChannel + row * pitch;
765 for (col = 0; col < wid; col++) {
766 pPixel = pScanline + col * image->numcomps;
767 if (!image->comps[channel].data) {
770 src = image->comps[channel].data[row * wid + col];
771 src += image->comps[channel].sgnd ? 1 << (image->comps[channel].prec - 1) : 0;
772 if (adjust_comps[channel] - 1 < 0) {
773 *pPixel = (FX_BYTE)((src >> adjust_comps[channel]));
775 int tmpPixel = (src >> adjust_comps[channel]) + ((src >> (adjust_comps[channel] - 1)) % 2);
776 if (tmpPixel > 255) {
778 } else if (tmpPixel < 0) {
781 *pPixel = (FX_BYTE)tmpPixel;
788 FX_Free(channel_bufs);
789 FX_Free(adjust_comps);
792 FX_Free(channel_bufs);
793 FX_Free(adjust_comps);
796 void initialize_transition_table();
797 void initialize_significance_luts();
798 void initialize_sign_lut();
799 CCodec_JpxModule::CCodec_JpxModule()
802 void* CCodec_JpxModule::CreateDecoder(FX_LPCBYTE src_buf, FX_DWORD src_size , FX_BOOL useColorSpace)
804 CJPX_Decoder* pDecoder = new CJPX_Decoder;
805 pDecoder->m_useColorSpace = useColorSpace;
806 if (!pDecoder->Init(src_buf, src_size)) {
812 void CCodec_JpxModule::GetImageInfo(FX_LPVOID ctx, FX_DWORD& width, FX_DWORD& height,
813 FX_DWORD& codestream_nComps, FX_DWORD& output_nComps)
815 CJPX_Decoder* pDecoder = (CJPX_Decoder*)ctx;
816 pDecoder->GetInfo(width, height, codestream_nComps, output_nComps);
818 FX_BOOL CCodec_JpxModule::Decode(void* ctx, FX_LPBYTE dest_data, int pitch, FX_BOOL bTranslateColor, FX_LPBYTE offsets)
820 CJPX_Decoder* pDecoder = (CJPX_Decoder*)ctx;
821 return pDecoder->Decode(dest_data, pitch, bTranslateColor, offsets);
823 void CCodec_JpxModule::DestroyDecoder(void* ctx)
825 CJPX_Decoder* pDecoder = (CJPX_Decoder*)ctx;