summaryrefslogtreecommitdiff
path: root/poppler/JPEG2000Stream.cc
diff options
context:
space:
mode:
authorAlbert Astals Cid <aacid@kde.org>2008-06-14 00:53:38 +0200
committerAlbert Astals Cid <aacid@kde.org>2008-06-14 00:53:38 +0200
commit99d2361032cbaafd69bd796170757ed6482f208d (patch)
tree5ae4ea49de13fd620971104c9d887abe2a512cdf /poppler/JPEG2000Stream.cc
parente368838d7f9691c7b1adf7d7f62f65abed91eea7 (diff)
Add a JPEG2000 decoder based on OpenJPEG
Enabled by default since it's generally better than xpdf one See http://lists.freedesktop.org/archives/poppler/2008-June/003874.html for more information
Diffstat (limited to 'poppler/JPEG2000Stream.cc')
-rw-r--r--poppler/JPEG2000Stream.cc181
1 files changed, 181 insertions, 0 deletions
diff --git a/poppler/JPEG2000Stream.cc b/poppler/JPEG2000Stream.cc
new file mode 100644
index 00000000..47908fb6
--- /dev/null
+++ b/poppler/JPEG2000Stream.cc
@@ -0,0 +1,181 @@
+//========================================================================
+//
+// JPEG2000Stream.cc
+//
+// A JPX stream decoder using OpenJPEG
+//
+// Copyright 2008 Albert Astals Cid <aacid@kde.org>
+//
+// Licensed under GPLv2 or later
+//
+//========================================================================
+
+#include "JPEG2000Stream.h"
+
+JPXStream::JPXStream(Stream *strA) : FilterStream(strA)
+{
+ inited = gFalse;
+ image = NULL;
+ dinfo = NULL;
+}
+
+JPXStream::~JPXStream() {
+ delete str;
+ close();
+}
+
+void JPXStream::reset() {
+ counter = 0;
+}
+
+void JPXStream::close() {
+ if (image != NULL) {
+ opj_image_destroy(image);
+ image = NULL;
+ }
+ if (dinfo != NULL) {
+ opj_destroy_decompress(dinfo);
+ dinfo = NULL;
+ }
+}
+
+int JPXStream::getPos() {
+ return counter;
+}
+
+int JPXStream::getChar() {
+ int result = lookChar();
+ ++counter;
+ return result;
+}
+
+#define BUFFER_INCREASE 4096
+
+void JPXStream::init()
+{
+ int bufSize = BUFFER_INCREASE;
+ unsigned char *buf = (unsigned char*)gmallocn(bufSize, sizeof(unsigned char));
+ int index = 0;
+
+ str->reset();
+ int c = str->getChar();
+ while(c != EOF)
+ {
+ buf[index] = c;
+ ++index;
+ if (index >= bufSize)
+ {
+ bufSize += BUFFER_INCREASE;
+ buf = (unsigned char*)greallocn(buf, bufSize, sizeof(unsigned char));
+ }
+ c = str->getChar();
+ }
+
+ init2(buf, index, CODEC_JP2);
+
+ free(buf);
+
+ counter = 0;
+ inited = gTrue;
+}
+
+static void libopenjpeg_error_callback(const char *msg, void * /*client_data*/) {
+ error(-1, (char*)msg);
+}
+
+static void libopenjpeg_warning_callback(const char *msg, void * /*client_data*/) {
+ error(-1, (char*)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(&parameters);
+
+ /* 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, &parameters);
+
+ /* 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() {
+ if (inited == gFalse) init();
+
+ if (!image) return EOF;
+
+ int w = image->comps[0].w;
+ int h = image->comps[0].h;
+
+ int y = (counter / image->numcomps) / w;
+ int x = (counter / image->numcomps) % w;
+ if (y >= h) return EOF;
+
+ int component = counter % image->numcomps;
+
+ int adjust = 0;
+ if (image->comps[component].prec > 8) {
+ adjust = image->comps[component].prec - 8;
+ }
+
+ int r = image->comps[component].data[y * w + x];
+ r += (image->comps[component].sgnd ? 1 << (image->comps[0].prec - 1) : 0);
+
+ unsigned char rc = (unsigned char) ((r >> adjust)+((r >> (adjust-1))%2));
+
+ return rc;
+}
+
+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;
+}
+