sinc with TL rev. 38618.
[luatex.git] / source / libs / poppler / poppler-0.37.0 / poppler / JPEG2000Stream.cc
blob35e98b86ebce67fc0d0097a167f61c4c1954bec5
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>
13 // Licensed under GPLv2 or later
15 //========================================================================
17 #include "config.h"
18 #include "JPEG2000Stream.h"
19 #include <openjpeg.h>
21 #define OPENJPEG_VERSION_ENCODE(major, minor, micro) ( \
22 ((major) * 10000) \
23 + ((minor) * 100) \
24 + ((micro) * 1))
26 #ifdef USE_OPENJPEG2
27 #ifdef OPJ_VERSION_MAJOR
28 #define OPENJPEG_VERSION OPENJPEG_VERSION_ENCODE(OPJ_VERSION_MAJOR, OPJ_VERSION_MINOR, OPJ_VERSION_BUILD)
29 #else
30 // OpenJPEG started providing version macros in version 2.1.
31 // If the version macro is not found, set the version to 2.0.0 and
32 // assume there will be no API changes in 2.0.x.
33 #define OPENJPEG_VERSION OPENJPEG_VERSION_ENCODE(2, 0, 0)
34 #endif
35 #endif
37 struct JPXStreamPrivate {
38 opj_image_t *image;
39 int counter;
40 int ccounter;
41 int npixels;
42 int ncomps;
43 GBool inited;
44 #ifdef USE_OPENJPEG1
45 opj_dinfo_t *dinfo;
46 void init2(unsigned char *buf, int bufLen, OPJ_CODEC_FORMAT format);
47 #endif
48 #ifdef USE_OPENJPEG2
49 void init2(OPJ_CODEC_FORMAT format, unsigned char *data, int length);
50 #endif
53 static inline int doLookChar(JPXStreamPrivate* priv) {
54 if (unlikely(priv->counter >= priv->npixels))
55 return EOF;
57 return ((unsigned char *)priv->image->comps[priv->ccounter].data)[priv->counter];
60 static inline int doGetChar(JPXStreamPrivate* priv) {
61 const int result = doLookChar(priv);
62 if (++priv->ccounter == priv->ncomps) {
63 priv->ccounter = 0;
64 ++priv->counter;
66 return result;
69 JPXStream::JPXStream(Stream *strA) : FilterStream(strA) {
70 priv = new JPXStreamPrivate;
71 priv->inited = gFalse;
72 priv->image = NULL;
73 priv->npixels = 0;
74 priv->ncomps = 0;
75 #ifdef USE_OPENJPEG1
76 priv->dinfo = NULL;
77 #endif
80 JPXStream::~JPXStream() {
81 delete str;
82 close();
83 delete priv;
86 void JPXStream::reset() {
87 priv->counter = 0;
88 priv->ccounter = 0;
91 void JPXStream::close() {
92 if (priv->image != NULL) {
93 opj_image_destroy(priv->image);
94 priv->image = NULL;
95 priv->npixels = 0;
98 #ifdef USE_OPENJPEG1
99 if (priv->dinfo != NULL) {
100 opj_destroy_decompress(priv->dinfo);
101 priv->dinfo = NULL;
103 #endif
106 Goffset JPXStream::getPos() {
107 return priv->counter * priv->ncomps + priv->ccounter;
110 int JPXStream::getChars(int nChars, Guchar *buffer) {
111 if (unlikely(priv->inited == gFalse)) { init(); }
113 for (int i = 0; i < nChars; ++i) {
114 const int c = doGetChar(priv);
115 if (likely(c != EOF)) buffer[i] = c;
116 else return i;
118 return nChars;
121 int JPXStream::getChar() {
122 if (unlikely(priv->inited == gFalse)) { init(); }
124 return doGetChar(priv);
127 int JPXStream::lookChar() {
128 if (unlikely(priv->inited == gFalse)) { init(); }
130 return doLookChar(priv);
133 GooString *JPXStream::getPSFilter(int psLevel, const char *indent) {
134 return NULL;
137 GBool JPXStream::isBinary(GBool last) {
138 return str->isBinary(gTrue);
141 void JPXStream::getImageParams(int *bitsPerComponent, StreamColorSpaceMode *csMode) {
142 if (unlikely(priv->inited == gFalse)) { init(); }
144 *bitsPerComponent = 8;
145 if (priv->image && priv->image->numcomps == 3)
146 *csMode = streamCSDeviceRGB;
147 else if (priv->image && priv->image->numcomps == 4)
148 *csMode = streamCSDeviceCMYK;
149 else
150 *csMode = streamCSDeviceGray;
154 static void libopenjpeg_error_callback(const char *msg, void * /*client_data*/) {
155 error(errSyntaxError, -1, "{0:s}", msg);
158 static void libopenjpeg_warning_callback(const char *msg, void * /*client_data*/) {
159 error(errSyntaxWarning, -1, "{0:s}", msg);
162 #ifdef USE_OPENJPEG1
164 #define BUFFER_INITIAL_SIZE 4096
166 void JPXStream::init()
168 Object oLen;
169 if (getDict()) getDict()->lookup("Length", &oLen);
171 int bufSize = BUFFER_INITIAL_SIZE;
172 if (oLen.isInt()) bufSize = oLen.getInt();
173 oLen.free();
175 int length = 0;
176 unsigned char *buf = str->toUnsignedChars(&length, bufSize);
177 priv->init2(buf, length, CODEC_JP2);
178 free(buf);
180 if (priv->image) {
181 priv->npixels = priv->image->comps[0].w * priv->image->comps[0].h;
182 priv->ncomps = priv->image->numcomps;
183 for (int component = 0; component < priv->ncomps; component++) {
184 if (priv->image->comps[component].data == NULL) {
185 close();
186 break;
188 unsigned char *cdata = (unsigned char *)priv->image->comps[component].data;
189 int adjust = 0;
190 if (priv->image->comps[component].prec > 8)
191 adjust = priv->image->comps[component].prec - 8;
192 int sgndcorr = 0;
193 if (priv->image->comps[component].sgnd)
194 sgndcorr = 1 << (priv->image->comps[0].prec - 1);
195 for (int i = 0; i < priv->npixels; i++) {
196 int r = priv->image->comps[component].data[i];
197 r += sgndcorr;
198 if (adjust) {
199 r = (r >> adjust)+((r >> (adjust-1))%2);
200 if (unlikely(r > 255))
201 r = 255;
203 *(cdata++) = r;
206 } else
207 priv->npixels = 0;
209 priv->counter = 0;
210 priv->ccounter = 0;
211 priv->inited = gTrue;
214 void JPXStreamPrivate::init2(unsigned char *buf, int bufLen, OPJ_CODEC_FORMAT format)
216 opj_cio_t *cio = NULL;
218 /* Use default decompression parameters */
219 opj_dparameters_t parameters;
220 opj_set_default_decoder_parameters(&parameters);
221 #ifdef WITH_OPENJPEG_IGNORE_PCLR_CMAP_CDEF_FLAG
222 parameters.flags = OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG;
223 #endif
225 /* Configure the event manager to receive errors and warnings */
226 opj_event_mgr_t event_mgr;
227 memset(&event_mgr, 0, sizeof(opj_event_mgr_t));
228 event_mgr.error_handler = libopenjpeg_error_callback;
229 event_mgr.warning_handler = libopenjpeg_warning_callback;
231 /* Get the decoder handle of the format */
232 dinfo = opj_create_decompress(format);
233 if (dinfo == NULL) goto error;
234 /* Catch events using our callbacks */
235 opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, NULL);
237 /* Setup the decoder decoding parameters */
238 opj_setup_decoder(dinfo, &parameters);
240 /* Open a byte stream */
241 cio = opj_cio_open((opj_common_ptr)dinfo, buf, bufLen);
242 if (cio == NULL) goto error;
244 /* Decode the stream and fill the image structure */
245 image = opj_decode(dinfo, cio);
247 /* Close the byte stream */
248 opj_cio_close(cio);
250 if (image == NULL) goto error;
251 else return;
253 error:
254 if (format == CODEC_JP2) {
255 error(errSyntaxWarning, -1, "Did no succeed opening JPX Stream as JP2, trying as J2K.");
256 init2(buf, bufLen, CODEC_J2K);
257 } else if (format == CODEC_J2K) {
258 error(errSyntaxWarning, -1, "Did no succeed opening JPX Stream as J2K, trying as JPT.");
259 init2(buf, bufLen, CODEC_JPT);
260 } else {
261 error(errSyntaxError, -1, "Did no succeed opening JPX Stream.");
264 #endif
267 #ifdef USE_OPENJPEG2
268 typedef struct JPXData_s
270 unsigned char *data;
271 int size;
272 int pos;
273 } JPXData;
275 #define BUFFER_INITIAL_SIZE 4096
277 static OPJ_SIZE_T jpxRead_callback(void * p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data)
279 JPXData *jpxData = (JPXData *)p_user_data;
280 int len;
282 len = jpxData->size - jpxData->pos;
283 if (len < 0)
284 len = 0;
285 if (len == 0)
286 return (OPJ_SIZE_T)-1; /* End of file! */
287 if ((OPJ_SIZE_T)len > p_nb_bytes)
288 len = p_nb_bytes;
289 memcpy(p_buffer, jpxData->data + jpxData->pos, len);
290 jpxData->pos += len;
291 return len;
294 static OPJ_OFF_T jpxSkip_callback(OPJ_OFF_T skip, void * p_user_data)
296 JPXData *jpxData = (JPXData *)p_user_data;
298 jpxData->pos += (skip > jpxData->size - jpxData->pos) ? jpxData->size - jpxData->pos : skip;
299 /* Always return input value to avoid "Problem with skipping JPEG2000 box, stream error" */
300 return skip;
303 static OPJ_BOOL jpxSeek_callback(OPJ_OFF_T seek_pos, void * p_user_data)
305 JPXData *jpxData = (JPXData *)p_user_data;
307 if (seek_pos > jpxData->size)
308 return OPJ_FALSE;
309 jpxData->pos = seek_pos;
310 return OPJ_TRUE;
313 void JPXStream::init()
315 Object oLen;
316 if (getDict()) getDict()->lookup("Length", &oLen);
318 int bufSize = BUFFER_INITIAL_SIZE;
319 if (oLen.isInt()) bufSize = oLen.getInt();
320 oLen.free();
322 int length = 0;
323 unsigned char *buf = str->toUnsignedChars(&length, bufSize);
324 priv->init2(OPJ_CODEC_JP2, buf, length);
325 gfree(buf);
327 if (priv->image) {
328 priv->npixels = priv->image->comps[0].w * priv->image->comps[0].h;
329 priv->ncomps = priv->image->numcomps;
330 for (int component = 0; component < priv->ncomps; component++) {
331 if (priv->image->comps[component].data == NULL) {
332 close();
333 break;
335 unsigned char *cdata = (unsigned char *)priv->image->comps[component].data;
336 int adjust = 0;
337 if (priv->image->comps[component].prec > 8)
338 adjust = priv->image->comps[component].prec - 8;
339 int sgndcorr = 0;
340 if (priv->image->comps[component].sgnd)
341 sgndcorr = 1 << (priv->image->comps[0].prec - 1);
342 for (int i = 0; i < priv->npixels; i++) {
343 int r = priv->image->comps[component].data[i];
344 r += sgndcorr;
345 if (adjust) {
346 r = (r >> adjust)+((r >> (adjust-1))%2);
347 if (unlikely(r > 255))
348 r = 255;
350 *(cdata++) = r;
353 } else {
354 priv->npixels = 0;
357 priv->counter = 0;
358 priv->ccounter = 0;
359 priv->inited = gTrue;
362 void JPXStreamPrivate::init2(OPJ_CODEC_FORMAT format, unsigned char *buf, int length)
364 JPXData jpxData;
366 jpxData.data = buf;
367 jpxData.pos = 0;
368 jpxData.size = length;
370 opj_stream_t *stream;
372 stream = opj_stream_default_create(OPJ_TRUE);
374 #if OPENJPEG_VERSION >= OPENJPEG_VERSION_ENCODE(2, 1, 0)
375 opj_stream_set_user_data (stream, &jpxData, NULL);
376 #else
377 opj_stream_set_user_data (stream, &jpxData);
378 #endif
380 opj_stream_set_read_function(stream, jpxRead_callback);
381 opj_stream_set_skip_function(stream, jpxSkip_callback);
382 opj_stream_set_seek_function(stream, jpxSeek_callback);
383 /* Set the length to avoid an assert */
384 opj_stream_set_user_data_length(stream, length);
386 opj_codec_t *decoder;
388 /* Use default decompression parameters */
389 opj_dparameters_t parameters;
390 opj_set_default_decoder_parameters(&parameters);
391 parameters.flags |= OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG;
393 /* Get the decoder handle of the format */
394 decoder = opj_create_decompress(format);
395 if (decoder == NULL) {
396 error(errSyntaxWarning, -1, "Unable to create decoder");
397 goto error;
400 /* Catch events using our callbacks */
401 opj_set_warning_handler(decoder, libopenjpeg_warning_callback, NULL);
402 opj_set_error_handler(decoder, libopenjpeg_error_callback, NULL);
404 /* Setup the decoder decoding parameters */
405 if (!opj_setup_decoder(decoder, &parameters)) {
406 error(errSyntaxWarning, -1, "Unable to set decoder parameters");
407 goto error;
410 /* Decode the stream and fill the image structure */
411 image = NULL;
412 if (!opj_read_header(stream, decoder, &image)) {
413 error(errSyntaxWarning, -1, "Unable to read header");
414 goto error;
417 /* Optional if you want decode the entire image */
418 if (!opj_set_decode_area(decoder, image, parameters.DA_x0,
419 parameters.DA_y0, parameters.DA_x1, parameters.DA_y1)){
420 error(errSyntaxWarning, -1, "X2");
421 goto error;
424 /* Get the decoded image */
425 if (!(opj_decode(decoder, stream, image) && opj_end_decompress(decoder, stream))) {
426 error(errSyntaxWarning, -1, "Unable to decode image");
427 goto error;
430 opj_destroy_codec(decoder);
431 opj_stream_destroy(stream);
433 if (image != NULL)
434 return;
436 error:
437 opj_destroy_codec(decoder);
438 if (format == OPJ_CODEC_JP2) {
439 error(errSyntaxWarning, -1, "Did no succeed opening JPX Stream as JP2, trying as J2K.");
440 init2(OPJ_CODEC_J2K, buf, length);
441 } else if (format == OPJ_CODEC_J2K) {
442 error(errSyntaxWarning, -1, "Did no succeed opening JPX Stream as J2K, trying as JPT.");
443 init2(OPJ_CODEC_JPT, buf, length);
444 } else {
445 error(errSyntaxError, -1, "Did no succeed opening JPX Stream.");
448 #endif