beta-0.89.2
[luatex.git] / source / libs / poppler / poppler-src / poppler / JPEG2000Stream.cc
blob4c632d717e9ddf07a53a7be685a71ba65ba6e0af
1 //========================================================================
2 //
3 // JPEG2000Stream.cc
4 //
5 // A JPX stream decoder using OpenJPEG
6 //
7 // Copyright 2008-2010, 2012 Albert Astals Cid <aacid@kde.org>
8 // Copyright 2011 Daniel Glöckner <daniel-gl@gmx.net>
9 // Copyright 2014 Thomas Freitag <Thomas.Freitag@alfa.de>
10 // Copyright 2013, 2014 Adrian Johnson <ajohnson@redneon.com>
11 // Copyright 2015 Adam Reichold <adam.reichold@t-online.de>
12 // Copyright 2015 Jakub Wilk <jwilk@jwilk.net>
14 // Licensed under GPLv2 or later
16 //========================================================================
18 #include "config.h"
19 #include "JPEG2000Stream.h"
20 #include <openjpeg.h>
22 #define OPENJPEG_VERSION_ENCODE(major, minor, micro) ( \
23 ((major) * 10000) \
24 + ((minor) * 100) \
25 + ((micro) * 1))
27 #ifdef USE_OPENJPEG2
28 #ifdef OPJ_VERSION_MAJOR
29 #define OPENJPEG_VERSION OPENJPEG_VERSION_ENCODE(OPJ_VERSION_MAJOR, OPJ_VERSION_MINOR, OPJ_VERSION_BUILD)
30 #else
31 // OpenJPEG started providing version macros in version 2.1.
32 // If the version macro is not found, set the version to 2.0.0 and
33 // assume there will be no API changes in 2.0.x.
34 #define OPENJPEG_VERSION OPENJPEG_VERSION_ENCODE(2, 0, 0)
35 #endif
36 #endif
38 struct JPXStreamPrivate {
39 opj_image_t *image;
40 int counter;
41 int ccounter;
42 int npixels;
43 int ncomps;
44 GBool inited;
45 #ifdef USE_OPENJPEG1
46 opj_dinfo_t *dinfo;
47 void init2(unsigned char *buf, int bufLen, OPJ_CODEC_FORMAT format);
48 #endif
49 #ifdef USE_OPENJPEG2
50 void init2(OPJ_CODEC_FORMAT format, unsigned char *data, int length);
51 #endif
54 static inline int doLookChar(JPXStreamPrivate* priv) {
55 if (unlikely(priv->counter >= priv->npixels))
56 return EOF;
58 return ((unsigned char *)priv->image->comps[priv->ccounter].data)[priv->counter];
61 static inline int doGetChar(JPXStreamPrivate* priv) {
62 const int result = doLookChar(priv);
63 if (++priv->ccounter == priv->ncomps) {
64 priv->ccounter = 0;
65 ++priv->counter;
67 return result;
70 JPXStream::JPXStream(Stream *strA) : FilterStream(strA) {
71 priv = new JPXStreamPrivate;
72 priv->inited = gFalse;
73 priv->image = NULL;
74 priv->npixels = 0;
75 priv->ncomps = 0;
76 #ifdef USE_OPENJPEG1
77 priv->dinfo = NULL;
78 #endif
81 JPXStream::~JPXStream() {
82 delete str;
83 close();
84 delete priv;
87 void JPXStream::reset() {
88 priv->counter = 0;
89 priv->ccounter = 0;
92 void JPXStream::close() {
93 if (priv->image != NULL) {
94 opj_image_destroy(priv->image);
95 priv->image = NULL;
96 priv->npixels = 0;
99 #ifdef USE_OPENJPEG1
100 if (priv->dinfo != NULL) {
101 opj_destroy_decompress(priv->dinfo);
102 priv->dinfo = NULL;
104 #endif
107 Goffset JPXStream::getPos() {
108 return priv->counter * priv->ncomps + priv->ccounter;
111 int JPXStream::getChars(int nChars, Guchar *buffer) {
112 if (unlikely(priv->inited == gFalse)) { init(); }
114 for (int i = 0; i < nChars; ++i) {
115 const int c = doGetChar(priv);
116 if (likely(c != EOF)) buffer[i] = c;
117 else return i;
119 return nChars;
122 int JPXStream::getChar() {
123 if (unlikely(priv->inited == gFalse)) { init(); }
125 return doGetChar(priv);
128 int JPXStream::lookChar() {
129 if (unlikely(priv->inited == gFalse)) { init(); }
131 return doLookChar(priv);
134 GooString *JPXStream::getPSFilter(int psLevel, const char *indent) {
135 return NULL;
138 GBool JPXStream::isBinary(GBool last) {
139 return str->isBinary(gTrue);
142 void JPXStream::getImageParams(int *bitsPerComponent, StreamColorSpaceMode *csMode) {
143 if (unlikely(priv->inited == gFalse)) { init(); }
145 *bitsPerComponent = 8;
146 if (priv->image && priv->image->numcomps == 3)
147 *csMode = streamCSDeviceRGB;
148 else if (priv->image && priv->image->numcomps == 4)
149 *csMode = streamCSDeviceCMYK;
150 else
151 *csMode = streamCSDeviceGray;
155 static void libopenjpeg_error_callback(const char *msg, void * /*client_data*/) {
156 error(errSyntaxError, -1, "{0:s}", msg);
159 static void libopenjpeg_warning_callback(const char *msg, void * /*client_data*/) {
160 error(errSyntaxWarning, -1, "{0:s}", msg);
163 #ifdef USE_OPENJPEG1
165 #define BUFFER_INITIAL_SIZE 4096
167 void JPXStream::init()
169 Object oLen;
170 if (getDict()) getDict()->lookup("Length", &oLen);
172 int bufSize = BUFFER_INITIAL_SIZE;
173 if (oLen.isInt()) bufSize = oLen.getInt();
174 oLen.free();
176 int length = 0;
177 unsigned char *buf = str->toUnsignedChars(&length, bufSize);
178 priv->init2(buf, length, CODEC_JP2);
179 free(buf);
181 if (priv->image) {
182 priv->npixels = priv->image->comps[0].w * priv->image->comps[0].h;
183 priv->ncomps = priv->image->numcomps;
184 for (int component = 0; component < priv->ncomps; component++) {
185 if (priv->image->comps[component].data == NULL) {
186 close();
187 break;
189 unsigned char *cdata = (unsigned char *)priv->image->comps[component].data;
190 int adjust = 0;
191 if (priv->image->comps[component].prec > 8)
192 adjust = priv->image->comps[component].prec - 8;
193 int sgndcorr = 0;
194 if (priv->image->comps[component].sgnd)
195 sgndcorr = 1 << (priv->image->comps[0].prec - 1);
196 for (int i = 0; i < priv->npixels; i++) {
197 int r = priv->image->comps[component].data[i];
198 r += sgndcorr;
199 if (adjust) {
200 r = (r >> adjust)+((r >> (adjust-1))%2);
201 if (unlikely(r > 255))
202 r = 255;
204 *(cdata++) = r;
207 } else
208 priv->npixels = 0;
210 priv->counter = 0;
211 priv->ccounter = 0;
212 priv->inited = gTrue;
215 void JPXStreamPrivate::init2(unsigned char *buf, int bufLen, OPJ_CODEC_FORMAT format)
217 opj_cio_t *cio = NULL;
219 /* Use default decompression parameters */
220 opj_dparameters_t parameters;
221 opj_set_default_decoder_parameters(&parameters);
222 #ifdef WITH_OPENJPEG_IGNORE_PCLR_CMAP_CDEF_FLAG
223 parameters.flags = OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG;
224 #endif
226 /* Configure the event manager to receive errors and warnings */
227 opj_event_mgr_t event_mgr;
228 memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
229 event_mgr.error_handler = libopenjpeg_error_callback;
230 event_mgr.warning_handler = libopenjpeg_warning_callback;
232 /* Get the decoder handle of the format */
233 dinfo = opj_create_decompress(format);
234 if (dinfo == NULL) goto error;
235 /* Catch events using our callbacks */
236 opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, NULL);
238 /* Setup the decoder decoding parameters */
239 opj_setup_decoder(dinfo, &parameters);
241 /* Open a byte stream */
242 cio = opj_cio_open((opj_common_ptr)dinfo, buf, bufLen);
243 if (cio == NULL) goto error;
245 /* Decode the stream and fill the image structure */
246 image = opj_decode(dinfo, cio);
248 /* Close the byte stream */
249 opj_cio_close(cio);
251 if (image == NULL) goto error;
252 else return;
254 error:
255 if (format == CODEC_JP2) {
256 error(errSyntaxWarning, -1, "Did not succeed opening JPX Stream as JP2, trying as J2K.");
257 init2(buf, bufLen, CODEC_J2K);
258 } else if (format == CODEC_J2K) {
259 error(errSyntaxWarning, -1, "Did not succeed opening JPX Stream as J2K, trying as JPT.");
260 init2(buf, bufLen, CODEC_JPT);
261 } else {
262 error(errSyntaxError, -1, "Did not succeed opening JPX Stream.");
265 #endif
268 #ifdef USE_OPENJPEG2
269 typedef struct JPXData_s
271 unsigned char *data;
272 int size;
273 int pos;
274 } JPXData;
276 #define BUFFER_INITIAL_SIZE 4096
278 static OPJ_SIZE_T jpxRead_callback(void * p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data)
280 JPXData *jpxData = (JPXData *)p_user_data;
281 int len;
283 len = jpxData->size - jpxData->pos;
284 if (len < 0)
285 len = 0;
286 if (len == 0)
287 return (OPJ_SIZE_T)-1; /* End of file! */
288 if ((OPJ_SIZE_T)len > p_nb_bytes)
289 len = p_nb_bytes;
290 memcpy(p_buffer, jpxData->data + jpxData->pos, len);
291 jpxData->pos += len;
292 return len;
295 static OPJ_OFF_T jpxSkip_callback(OPJ_OFF_T skip, void * p_user_data)
297 JPXData *jpxData = (JPXData *)p_user_data;
299 jpxData->pos += (skip > jpxData->size - jpxData->pos) ? jpxData->size - jpxData->pos : skip;
300 /* Always return input value to avoid "Problem with skipping JPEG2000 box, stream error" */
301 return skip;
304 static OPJ_BOOL jpxSeek_callback(OPJ_OFF_T seek_pos, void * p_user_data)
306 JPXData *jpxData = (JPXData *)p_user_data;
308 if (seek_pos > jpxData->size)
309 return OPJ_FALSE;
310 jpxData->pos = seek_pos;
311 return OPJ_TRUE;
314 void JPXStream::init()
316 Object oLen;
317 if (getDict()) getDict()->lookup("Length", &oLen);
319 int bufSize = BUFFER_INITIAL_SIZE;
320 if (oLen.isInt()) bufSize = oLen.getInt();
321 oLen.free();
323 int length = 0;
324 unsigned char *buf = str->toUnsignedChars(&length, bufSize);
325 priv->init2(OPJ_CODEC_JP2, buf, length);
326 gfree(buf);
328 if (priv->image) {
329 priv->npixels = priv->image->comps[0].w * priv->image->comps[0].h;
330 priv->ncomps = priv->image->numcomps;
331 for (int component = 0; component < priv->ncomps; component++) {
332 if (priv->image->comps[component].data == NULL) {
333 close();
334 break;
336 unsigned char *cdata = (unsigned char *)priv->image->comps[component].data;
337 int adjust = 0;
338 if (priv->image->comps[component].prec > 8)
339 adjust = priv->image->comps[component].prec - 8;
340 int sgndcorr = 0;
341 if (priv->image->comps[component].sgnd)
342 sgndcorr = 1 << (priv->image->comps[0].prec - 1);
343 for (int i = 0; i < priv->npixels; i++) {
344 int r = priv->image->comps[component].data[i];
345 r += sgndcorr;
346 if (adjust) {
347 r = (r >> adjust)+((r >> (adjust-1))%2);
348 if (unlikely(r > 255))
349 r = 255;
351 *(cdata++) = r;
354 } else {
355 priv->npixels = 0;
358 priv->counter = 0;
359 priv->ccounter = 0;
360 priv->inited = gTrue;
363 void JPXStreamPrivate::init2(OPJ_CODEC_FORMAT format, unsigned char *buf, int length)
365 JPXData jpxData;
367 jpxData.data = buf;
368 jpxData.pos = 0;
369 jpxData.size = length;
371 opj_stream_t *stream;
373 stream = opj_stream_default_create(OPJ_TRUE);
375 #if OPENJPEG_VERSION >= OPENJPEG_VERSION_ENCODE(2, 1, 0)
376 opj_stream_set_user_data (stream, &jpxData, NULL);
377 #else
378 opj_stream_set_user_data (stream, &jpxData);
379 #endif
381 opj_stream_set_read_function(stream, jpxRead_callback);
382 opj_stream_set_skip_function(stream, jpxSkip_callback);
383 opj_stream_set_seek_function(stream, jpxSeek_callback);
384 /* Set the length to avoid an assert */
385 opj_stream_set_user_data_length(stream, length);
387 opj_codec_t *decoder;
389 /* Use default decompression parameters */
390 opj_dparameters_t parameters;
391 opj_set_default_decoder_parameters(&parameters);
392 parameters.flags |= OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG;
394 /* Get the decoder handle of the format */
395 decoder = opj_create_decompress(format);
396 if (decoder == NULL) {
397 error(errSyntaxWarning, -1, "Unable to create decoder");
398 goto error;
401 /* Catch events using our callbacks */
402 opj_set_warning_handler(decoder, libopenjpeg_warning_callback, NULL);
403 opj_set_error_handler(decoder, libopenjpeg_error_callback, NULL);
405 /* Setup the decoder decoding parameters */
406 if (!opj_setup_decoder(decoder, &parameters)) {
407 error(errSyntaxWarning, -1, "Unable to set decoder parameters");
408 goto error;
411 /* Decode the stream and fill the image structure */
412 image = NULL;
413 if (!opj_read_header(stream, decoder, &image)) {
414 error(errSyntaxWarning, -1, "Unable to read header");
415 goto error;
418 /* Optional if you want decode the entire image */
419 if (!opj_set_decode_area(decoder, image, parameters.DA_x0,
420 parameters.DA_y0, parameters.DA_x1, parameters.DA_y1)){
421 error(errSyntaxWarning, -1, "X2");
422 goto error;
425 /* Get the decoded image */
426 if (!(opj_decode(decoder, stream, image) && opj_end_decompress(decoder, stream))) {
427 error(errSyntaxWarning, -1, "Unable to decode image");
428 goto error;
431 opj_destroy_codec(decoder);
432 opj_stream_destroy(stream);
434 if (image != NULL)
435 return;
437 error:
438 opj_destroy_codec(decoder);
439 if (format == OPJ_CODEC_JP2) {
440 error(errSyntaxWarning, -1, "Did no succeed opening JPX Stream as JP2, trying as J2K.");
441 init2(OPJ_CODEC_J2K, buf, length);
442 } else if (format == OPJ_CODEC_J2K) {
443 error(errSyntaxWarning, -1, "Did no succeed opening JPX Stream as J2K, trying as JPT.");
444 init2(OPJ_CODEC_JPT, buf, length);
445 } else {
446 error(errSyntaxError, -1, "Did no succeed opening JPX Stream.");
449 #endif