From 95d36042d441d6c85b6d0d4ec094f67d0855f6bb Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 1 Jan 2013 21:06:38 +1030 Subject: [PATCH] initial attempt at libopenjpeg2 support --- configure.ac | 53 ++++++++--- poppler/JPEG2000Stream2.cc | 212 ++++++++++++++++++++++++++++++++++++++++++++ poppler/JPEG2000Stream2.h | 74 ++++++++++++++++ poppler/Makefile.am | 14 +++ 4 files changed, 343 insertions(+), 10 deletions(-) create mode 100644 poppler/JPEG2000Stream2.cc create mode 100644 poppler/JPEG2000Stream2.h diff --git a/configure.ac b/configure.ac index c2d6bdd..3f6ec8e 100644 --- a/configure.ac +++ b/configure.ac @@ -155,6 +155,8 @@ then fi +openjpeg1="no" +openjpeg2="no" dnl Test for libopenjpeg. Versions prior to 1.4 do not provide a pkgconfig file. AC_ARG_ENABLE(libopenjpeg, AC_HELP_STRING([--disable-libopenjpeg], @@ -170,17 +172,40 @@ if test x$enable_libopenjpeg = xyes; then AC_CHECK_HEADERS([openjpeg.h],, AC_MSG_ERROR("*** libopenjpeg headers not found ***"))]) elif test x$enable_libopenjpeg = xtry; then - PKG_CHECK_MODULES(LIBOPENJPEG, libopenjpeg, - [enable_libopenjpeg="yes"], - [AC_CHECK_LIB([openjpeg], [opj_cio_open], - [enable_libopenjpeg="yes" - LIBOPENJPEG_LIBS="-lopenjpeg"], - [enable_libopenjpeg="no"]) - AC_CHECK_HEADERS([openjpeg.h],, - [enable_libopenjpeg="no"])]) + dnl Check for openjpeg2 + AC_CHECK_LIB([openjp2], [opj_stream_default_create], + [openjpeg2="yes" + LIBOPENJPEG_LIBS="-lopenjp2"], + [openjpeg2="no"]) + AC_CHECK_HEADERS([openjpeg.h],, + [openjpeg2="no"]) + dnl Check for openjpeg1 + if test x$openjpeg2 != xyes; then + PKG_CHECK_MODULES(LIBOPENJPEG, libopenjpeg, + [openjpeg1="yes"], + [AC_CHECK_LIB([openjpeg], [opj_cio_open], + [openjpeg1="yes" + LIBOPENJPEG_LIBS="-lopenjpeg"], + [openjpeg1="no"]) + AC_CHECK_HEADERS([openjpeg.h],, + [openjpeg1="no"])]) + fi fi -if test x$enable_libopenjpeg = xyes; then +if test x$openjpeg1 = xyes || test x$openjpeg2 = xyes; then + enable_libopenjpeg=yes + if test x$openjpeg1 = xyes; then + AC_DEFINE(USE_OPENJPEG1, 1, [Defined if using openjpeg1]) + fi + if test x$openjpeg2 = xyes; then + AC_DEFINE(USE_OPENJPEG2, 1, [Defined if using openjpeg2]) + fi +fi + +AM_CONDITIONAL(USE_OPENJPEG1, test x$openjpeg1 = xyes) +AM_CONDITIONAL(USE_OPENJPEG2, test x$openjpeg2 = xyes) + +if test x$openjpeg1 = xyes || test x$openjpeg2 = xyes; then AC_SUBST(LIBOPENJPEG_CFLAGS) AC_SUBST(LIBOPENJPEG_LIBS) AC_DEFINE(ENABLE_LIBOPENJPEG) @@ -189,7 +214,8 @@ if test x$enable_libopenjpeg = xyes; then []) fi -AM_CONDITIONAL(BUILD_LIBOPENJPEG, test x$enable_libopenjpeg = xyes) +AM_CONDITIONAL(BUILD_LIBOPENJPEG, test x$openjpeg1 = xyes) +AM_CONDITIONAL(BUILD_LIBOPENJPEG2, test x$openjpeg2 = xyes) AH_TEMPLATE([ENABLE_LIBOPENJPEG], [Use libopenjpeg instead of builtin jpeg2000 decoder.]) @@ -820,6 +846,13 @@ echo " use libtiff: $enable_libtiff" echo " use zlib: $enable_zlib" echo " use libcurl: $enable_libcurl" echo " use libopenjpeg: $enable_libopenjpeg" +if test x$enable_libopenjpeg = xyes;then + if test x$openjpeg1 = xyes;then + echo " with openjpeg1" + else + echo " with openjpeg2" + fi +fi echo " use cms: $enable_cms" if test x$enable_cms = xyes;then if test x$lcms1 = xyes;then diff --git a/poppler/JPEG2000Stream2.cc b/poppler/JPEG2000Stream2.cc new file mode 100644 index 0000000..23fc182 --- /dev/null +++ b/poppler/JPEG2000Stream2.cc @@ -0,0 +1,212 @@ +//======================================================================== +// +// JPEG2000Stream.cc +// +// A JPX stream decoder using OpenJPEG +// +// Copyright 2008-2010, 2012 Albert Astals Cid +// Copyright 2011 Daniel Glöckner +// +// Licensed under GPLv2 or later +// +//======================================================================== + + +#include "JPEG2000Stream2.h" + +JPXStream::JPXStream(Stream *strA) : FilterStream(strA) +{ + inited = gFalse; + image = NULL; + npixels = 0; + ncomps = 0; +} + +JPXStream::~JPXStream() { + delete str; + close(); +} + +void JPXStream::reset() { + counter = 0; + ccounter = 0; + str->reset(); +} + +void JPXStream::close() { + if (image != NULL) { + opj_image_destroy(image); + image = NULL; + npixels = 0; + } +} + +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(); +} + +static OPJ_SIZE_T readStream_callback(void *buffer, OPJ_SIZE_T nBytes, void *userData) +{ + int len; + JPXStream *p = (JPXStream *)userData; + + len = p->readStream(nBytes, (Guchar*)buffer); + if (len == 0) + return (OPJ_SIZE_T)-1; + else + return len; +} + +void JPXStream::init() +{ + opj_stream_t *stream; + + str->reset(); + stream = opj_stream_default_create(OPJ_TRUE); + opj_stream_set_user_data (stream, this); + opj_stream_set_read_function(stream, readStream_callback); + + init2(stream, OPJ_CODEC_JP2); + + opj_stream_destroy(stream); + + 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(errSyntaxError, -1, "{0:s}", msg); +} + +static void libopenjpeg_warning_callback(const char *msg, void * /*client_data*/) { + error(errSyntaxWarning, -1, "{0:s}", msg); +} + +void JPXStream::init2(opj_stream_t *stream, OPJ_CODEC_FORMAT format) +{ + opj_codec_t *decoder; + + /* Use default decompression parameters */ + opj_dparameters_t parameters; + opj_set_default_decoder_parameters(¶meters); + parameters.flags |= OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG; + + /* Get the decoder handle of the format */ + decoder = opj_create_decompress(format); + if (decoder == NULL) { + error(errSyntaxWarning, -1, "Unable to create decoder"); + goto error; + } + + /* Catch events using our callbacks */ + opj_set_warning_handler(decoder, libopenjpeg_warning_callback, NULL); + opj_set_error_handler(decoder, libopenjpeg_error_callback, NULL); + + /* Setup the decoder decoding parameters */ + if (!opj_setup_decoder(decoder, ¶meters)) { + error(errSyntaxWarning, -1, "Unable to set decoder parameters"); + goto error; + } + + /* Decode the stream and fill the image structure */ + image = NULL; + if (!opj_read_header(stream, decoder, &image)) { + error(errSyntaxWarning, -1, "Unable to read header"); + goto error; + } + + /* Optional if you want decode the entire image */ + if (!opj_set_decode_area(decoder, image, parameters.DA_x0, + parameters.DA_y0, parameters.DA_x1, parameters.DA_y1)){ + error(errSyntaxWarning, -1, "X2"); + goto error; + } + + /* Get the decoded image */ + if (!(opj_decode(decoder, stream, image) && opj_end_decompress(decoder, stream))) { + error(errSyntaxWarning, -1, "Unable to decode image"); + goto error; + } + + opj_destroy_codec(decoder); + + if (image != NULL) + return; + +error: + if (format == OPJ_CODEC_JP2) { + error(errSyntaxWarning, -1, "Did no succeed opening JPX Stream as JP2, trying as J2K."); + init2(stream, OPJ_CODEC_J2K); + } else if (format == OPJ_CODEC_J2K) { + error(errSyntaxWarning, -1, "Did no succeed opening JPX Stream as J2K, trying as JPT."); + init2(stream, OPJ_CODEC_JPT); + } else { + error(errSyntaxError, -1, "Did no succeed opening JPX Stream."); + } +} + +int JPXStream::lookChar() { + return doLookChar(); +} + +GooString *JPXStream::getPSFilter(int psLevel, const 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; +} + diff --git a/poppler/JPEG2000Stream2.h b/poppler/JPEG2000Stream2.h new file mode 100644 index 0000000..2104adb --- /dev/null +++ b/poppler/JPEG2000Stream2.h @@ -0,0 +1,74 @@ +//======================================================================== +// +// JPEG2000Stream.h +// +// A JPX stream decoder using OpenJPEG +// +// Copyright 2008, 2010 Albert Astals Cid +// Copyright 2011 Daniel Glöckner +// +// Licensed under GPLv2 or later +// +//======================================================================== + + +#ifndef JPEG2000STREAM_H +#define JPEG2000STREAM_H + +#include "goo/gtypes.h" +#include "Object.h" +#include "Stream.h" +#include + +class JPXStream: public FilterStream { +public: + + JPXStream(Stream *strA); + virtual ~JPXStream(); + virtual StreamKind getKind() { return strJPX; } + virtual void reset(); + virtual void close(); + virtual int getPos(); + virtual int getChar(); + virtual int lookChar(); + virtual GooString *getPSFilter(int psLevel, const char *indent); + virtual GBool isBinary(GBool last = gTrue); + virtual void getImageParams(int *bitsPerComponent, StreamColorSpaceMode *csMode); + + int readStream(int nChars, Guchar *buffer) { + return str->doGetChars(nChars, buffer); + } + +private: + void init(); + void init2(opj_stream_t *stream, OPJ_CODEC_FORMAT format); + + virtual GBool hasGetChars() { return true; } + virtual int getChars(int nChars, Guchar *buffer); + + inline int doGetChar() { + int result = doLookChar(); + if (++ccounter == ncomps) { + ccounter = 0; + ++counter; + } + return result; + } + + inline int doLookChar() { + if (unlikely(inited == gFalse)) init(); + + if (unlikely(counter >= npixels)) return EOF; + + return ((unsigned char *)image->comps[ccounter].data)[counter]; + } + + opj_image_t *image; + int counter; + int ccounter; + int npixels; + int ncomps; + GBool inited; +}; + +#endif diff --git a/poppler/Makefile.am b/poppler/Makefile.am index c25ab03..d0406e4 100644 --- a/poppler/Makefile.am +++ b/poppler/Makefile.am @@ -84,6 +84,7 @@ libtiff_includes = \ endif + if BUILD_LIBOPENJPEG libjpeg2000_sources = \ @@ -96,12 +97,25 @@ libjpeg2000_includes = \ $(LIBOPENJPEG_CFLAGS) else +if BUILD_LIBOPENJPEG2 + +libjpeg2000_sources = \ + JPEG2000Stream2.h \ + JPEG2000Stream2.cc + +libjpeg2000_libs = \ + $(LIBOPENJPEG_LIBS) +libjpeg2000_includes = \ + $(LIBOPENJPEG_CFLAGS) + +else libjpeg2000_sources = \ JPXStream.h \ JPXStream.cc endif +endif if BUILD_ZLIB -- 1.7.10.4