//======================================================================== // // JPEG2000Stream.cc // // A JPX stream decoder using OpenJPEG // // Copyright 2008-2010 Albert Astals Cid // Copyright 2011 Daniel Glöckner // // Licensed under GPLv2 or later // //======================================================================== #include "JPEG2000Stream.h" JPXStream::JPXStream(Stream *strA) : FilterStream(strA) { inited = gFalse; image = NULL; dinfo = NULL; npixels = 0; ncomps = 0; } JPXStream::~JPXStream() { delete str; close(); } void JPXStream::reset() { counter = 0; ccounter = 0; } void JPXStream::close() { if (image != NULL) { opj_image_destroy(image); image = NULL; npixels = 0; } if (dinfo != NULL) { opj_destroy_decompress(dinfo); dinfo = NULL; } } int JPXStream::getPos() { return counter * ncomps + ccounter; } int JPXStream::getChars(int nChars, Guchar *buffer) { for (int i = 0; i < nChars; ++i) { const int c = doGetChar(); if (likely(c != EOF)) buffer[i] = c; else return i; } return nChars; } int JPXStream::getChar() { return doGetChar(); } #define BUFFER_INITIAL_SIZE 4096 void JPXStream::init() { Object oLen; if (getDict()) getDict()->lookup("Length", &oLen); int bufSize = BUFFER_INITIAL_SIZE; if (oLen.isInt()) bufSize = oLen.getInt(); oLen.free(); int length = 0; unsigned char *buf = str->toUnsignedChars(&length, bufSize); init2(buf, length, CODEC_JP2); free(buf); if (image) { npixels = image->comps[0].w * image->comps[0].h; ncomps = image->numcomps; for (int component = 0; component < ncomps; component++) { if (image->comps[component].data == NULL) { close(); break; } unsigned char *cdata = (unsigned char *)image->comps[component].data; int adjust = 0; if (image->comps[component].prec > 8) adjust = image->comps[component].prec - 8; int sgndcorr = 0; if (image->comps[component].sgnd) sgndcorr = 1 << (image->comps[0].prec - 1); for (int i = 0; i < npixels; i++) { int r = image->comps[component].data[i]; r += sgndcorr; if (adjust) { r = (r >> adjust)+((r >> (adjust-1))%2); if (unlikely(r > 255)) r = 255; } *(cdata++) = r; } } } else npixels = 0; counter = 0; ccounter = 0; inited = gTrue; } static void libopenjpeg_error_callback(const char *msg, void * /*client_data*/) { error(-1, "%s", msg); } static void libopenjpeg_warning_callback(const char *msg, void * /*client_data*/) { error(-1, "%s", msg); } void JPXStream::init2(unsigned char *buf, int bufLen, OPJ_CODEC_FORMAT format) { opj_cio_t *cio = NULL; /* Use default decompression parameters */ opj_dparameters_t parameters; opj_set_default_decoder_parameters(¶meters); /* Configure the event manager to receive errors and warnings */ opj_event_mgr_t event_mgr; memset(&event_mgr, 0, sizeof(opj_event_mgr_t)); event_mgr.error_handler = libopenjpeg_error_callback; event_mgr.warning_handler = libopenjpeg_warning_callback; /* Get the decoder handle of the format */ dinfo = opj_create_decompress(format); if (dinfo == NULL) goto error; /* Catch events using our callbacks */ opj_set_event_mgr((opj_common_ptr)dinfo, &event_mgr, NULL); /* Setup the decoder decoding parameters */ opj_setup_decoder(dinfo, ¶meters); /* Open a byte stream */ cio = opj_cio_open((opj_common_ptr)dinfo, buf, bufLen); if (cio == NULL) goto error; /* Decode the stream and fill the image structure */ image = opj_decode(dinfo, cio); /* Close the byte stream */ opj_cio_close(cio); if (image == NULL) goto error; else return; error: if (format == CODEC_JP2) { error(-1, "Did no succeed opening JPX Stream as JP2, trying as J2K."); init2(buf, bufLen, CODEC_J2K); } else if (format == CODEC_J2K) { error(-1, "Did no succeed opening JPX Stream as J2K, trying as JPT."); init2(buf, bufLen, CODEC_JPT); } else { error(-1, "Did no succeed opening JPX Stream."); } } int JPXStream::lookChar() { return doLookChar(); } GooString *JPXStream::getPSFilter(int psLevel, char *indent) { return NULL; } GBool JPXStream::isBinary(GBool last) { return str->isBinary(gTrue); } void JPXStream::getImageParams(int *bitsPerComponent, StreamColorSpaceMode *csMode) { if (inited == gFalse) init(); *bitsPerComponent = 8; if (image && image->numcomps == 3) *csMode = streamCSDeviceRGB; else *csMode = streamCSDeviceGray; }