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