diff --git a/configure.ac b/configure.ac index fdfe570..33bbe64 100644 --- a/configure.ac +++ b/configure.ac @@ -142,6 +142,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], @@ -149,25 +151,47 @@ AC_ARG_ENABLE(libopenjpeg, enable_libopenjpeg=$enableval, enable_libopenjpeg="try") if test x$enable_libopenjpeg = xyes; then - PKG_CHECK_MODULES(LIBOPENJPEG, libopenjpeg, - [], - [AC_CHECK_LIB([openjpeg], [opj_cio_open], - LIBOPENJPEG_LIBS="-lopenjpeg", - AC_MSG_ERROR("*** libopenjpeg library not found ***")) - AC_CHECK_HEADERS([openjpeg.h],, - AC_MSG_ERROR("*** libopenjpeg headers not found ***"))]) + PKG_CHECK_MODULES(LIBOPENJPEG, libopenjp2, + [openjpeg2="yes"], + [PKG_CHECK_MODULES(LIBOPENJPEG, libopenjpeg, + [openjpeg1="yes"], + [AC_CHECK_LIB([openjpeg], [opj_cio_open], + [openjpeg1="yes" + LIBOPENJPEG_LIBS="-lopenjpeg"], + AC_MSG_ERROR("*** libopenjpeg library not found ***")) + 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"])]) + PKG_CHECK_MODULES(LIBOPENJPEG, libopenjp2, + [openjpeg2="yes" + enable_libopenjpeg="yes"], + [PKG_CHECK_MODULES(LIBOPENJPEG, libopenjpeg, + [openjpeg1="yes" + enable_libopenjpeg="yes"], + [AC_CHECK_LIB([openjpeg], [opj_cio_open], + [openjpeg1="yes" + enable_libopenjpeg="yes" + LIBOPENJPEG_LIBS="-lopenjpeg"], + [enable_libopenjpeg="no"]) + AC_CHECK_HEADERS([openjpeg.h],, + [enable_libopenjpeg="no"])])]) +fi + +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 -if test x$enable_libopenjpeg = xyes; then +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) @@ -179,7 +203,7 @@ 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 || test x$openjpeg2 = xyes) AH_TEMPLATE([ENABLE_LIBOPENJPEG], [Use libopenjpeg instead of builtin jpeg2000 decoder.]) @@ -888,6 +912,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/JPEG2000Stream.cc b/poppler/JPEG2000Stream.cc index 703d471..24499fb 100644 --- a/poppler/JPEG2000Stream.cc +++ b/poppler/JPEG2000Stream.cc @@ -6,23 +6,26 @@ // // Copyright 2008-2010, 2012 Albert Astals Cid // Copyright 2011 Daniel Glöckner -// Copyright 2013 Adrian Johnson +// Copyright 2013,2014 Adrian Johnson // // Licensed under GPLv2 or later // //======================================================================== +#include "config.h" + #include "JPEG2000Stream.h" -#include "config.h" JPXStream::JPXStream(Stream *strA) : FilterStream(strA) { inited = gFalse; image = NULL; - dinfo = NULL; npixels = 0; ncomps = 0; +#ifdef USE_OPENJPEG1 + dinfo = NULL; +#endif } JPXStream::~JPXStream() { @@ -33,6 +36,9 @@ JPXStream::~JPXStream() { void JPXStream::reset() { counter = 0; ccounter = 0; +#ifdef USE_OPENJPEG1 + str->reset(); +#endif } void JPXStream::close() { @@ -41,10 +47,14 @@ void JPXStream::close() { image = NULL; npixels = 0; } + +#ifdef USE_OPENJPEG1 if (dinfo != NULL) { opj_destroy_decompress(dinfo); dinfo = NULL; } +#endif + } Goffset JPXStream::getPos() { @@ -64,6 +74,42 @@ int JPXStream::getChar() { return doGetChar(); } + +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 if (image && image->numcomps == 4) + *csMode = streamCSDeviceCMYK; + else + *csMode = streamCSDeviceGray; +} + + +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); +} + +#ifdef USE_OPENJPEG1 + #define BUFFER_INITIAL_SIZE 4096 void JPXStream::init() @@ -75,7 +121,6 @@ void JPXStream::init() if (oLen.isInt()) bufSize = oLen.getInt(); oLen.free(); - int length = 0; unsigned char *buf = str->toUnsignedChars(&length, bufSize); init2(buf, length, CODEC_JP2); @@ -115,14 +160,6 @@ void JPXStream::init() 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(unsigned char *buf, int bufLen, OPJ_CODEC_FORMAT format) { opj_cio_t *cio = NULL; @@ -174,24 +211,180 @@ error: error(errSyntaxError, -1, "Did no succeed opening JPX Stream."); } } +#endif -int JPXStream::lookChar() { - return doLookChar(); + +#ifdef USE_OPENJPEG2 +typedef struct JPXData_s +{ + unsigned char *data; + int size; + int pos; +} JPXData; + +#define BUFFER_INITIAL_SIZE 4096 + +static OPJ_SIZE_T jpxRead_callback(void * p_buffer, OPJ_SIZE_T p_nb_bytes, void * p_user_data) +{ + JPXData *jpxData = (JPXData *)p_user_data; + int len; + + len = jpxData->size - jpxData->pos; + if (len < 0) + len = 0; + if (len == 0) + return (OPJ_SIZE_T)-1; /* End of file! */ + if ((OPJ_SIZE_T)len > p_nb_bytes) + len = p_nb_bytes; + memcpy(p_buffer, jpxData->data + jpxData->pos, len); + jpxData->pos += len; + return len; } -GooString *JPXStream::getPSFilter(int psLevel, const char *indent) { - return NULL; +static OPJ_OFF_T jpxSkip_callback(OPJ_OFF_T skip, void * p_user_data) +{ + JPXData *jpxData = (JPXData *)p_user_data; + + jpxData->pos += (skip > jpxData->size - jpxData->pos) ? jpxData->size - jpxData->pos : skip; + /* Always return input value to avoid "Problem with skipping JPEG2000 box, stream error" */ + return skip; } -GBool JPXStream::isBinary(GBool last) { - return str->isBinary(gTrue); +static OPJ_BOOL jpxSeek_callback(OPJ_OFF_T seek_pos, void * p_user_data) +{ + JPXData *jpxData = (JPXData *)p_user_data; + + if (seek_pos > jpxData->size) + return OPJ_FALSE; + jpxData->pos = seek_pos; + return OPJ_TRUE; } -void JPXStream::getImageParams(int *bitsPerComponent, StreamColorSpaceMode *csMode) { - if (inited == gFalse) init(); +void JPXStream::init() +{ + Object oLen; + if (getDict()) getDict()->lookup("Length", &oLen); - *bitsPerComponent = 8; - if (image && image->numcomps == 3) *csMode = streamCSDeviceRGB; - else *csMode = streamCSDeviceGray; + int bufSize = BUFFER_INITIAL_SIZE; + if (oLen.isInt()) bufSize = oLen.getInt(); + oLen.free(); + + int length = 0; + unsigned char *buf = str->toUnsignedChars(&length, bufSize); + JPXData jpxData; + + jpxData.data = buf; + jpxData.pos = 0; + jpxData.size = length; + + opj_stream_t *stream; + + stream = opj_stream_default_create(OPJ_TRUE); + + opj_stream_set_user_data (stream, &jpxData); + opj_stream_set_read_function(stream, jpxRead_callback); + opj_stream_set_skip_function(stream, jpxSkip_callback); + opj_stream_set_seek_function(stream, jpxSeek_callback); + /* Set the length to avoid an assert */ + opj_stream_set_user_data_length(stream, length); + + 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_info_callback(const char *msg, void * /*client_data*/) { +// fprintf(stderr, "INFO: %s\n", 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); +// opj_set_info_handler(decoder, libopenjpeg_info_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; + } + + /* 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."); + } +} + +#endif diff --git a/poppler/JPEG2000Stream.h b/poppler/JPEG2000Stream.h index 3feccbe..b020ed7 100644 --- a/poppler/JPEG2000Stream.h +++ b/poppler/JPEG2000Stream.h @@ -6,7 +6,7 @@ // // Copyright 2008, 2010 Albert Astals Cid // Copyright 2011 Daniel Glöckner -// Copyright 2013 Adrian Johnson +// Copyright 2013,2014 Adrian Johnson // // Licensed under GPLv2 or later // @@ -16,6 +16,8 @@ #ifndef JPEG2000STREAM_H #define JPEG2000STREAM_H +#include "config.h" + #include #include "goo/gtypes.h" @@ -37,9 +39,17 @@ public: 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(); +#ifdef USE_OPENJPEG1 void init2(unsigned char *buf, int bufLen, OPJ_CODEC_FORMAT format); +#endif +#ifdef USE_OPENJPEG2 + void init2(opj_stream_t *stream, OPJ_CODEC_FORMAT format); +#endif virtual GBool hasGetChars() { return true; } virtual int getChars(int nChars, Guchar *buffer); @@ -62,12 +72,14 @@ private: } opj_image_t *image; - opj_dinfo_t *dinfo; int counter; int ccounter; int npixels; int ncomps; GBool inited; +#ifdef USE_OPENJPEG1 + opj_dinfo_t *dinfo; +#endif }; #endif