CMakeLists.txt | 56 ++++- cmake/modules/FindLIBOPENJPEG2.cmake | 30 ++ configure.ac | 80 +++++-- poppler/JPEG2000Stream.cc | 366 +++++++++++++++++++++++++++++------ poppler/JPEG2000Stream.h | 41 +-- 5 files changed, 453 insertions(+), 120 deletions(-)
New commits: commit e499fdab2e96cb3069db7ac8ffa0df20ccccddc9 Author: Thomas Freitag <[email protected]> Date: Sun Jan 4 20:23:39 2015 +0100 extended openjpeg2 support diff --git a/poppler/JPEG2000Stream.cc b/poppler/JPEG2000Stream.cc index 77a153b..2d48899 100644 --- a/poppler/JPEG2000Stream.cc +++ b/poppler/JPEG2000Stream.cc @@ -6,6 +6,7 @@ // // Copyright 2008-2010, 2012 Albert Astals Cid <[email protected]> // Copyright 2011 Daniel Glöckner <[email protected]> +// Copyright 2014 Thomas Freitag <[email protected]> // Copyright 2013,2014 Adrian Johnson <[email protected]> // // Licensed under GPLv2 or later @@ -44,7 +45,7 @@ struct JPXStreamPrivate { 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); + void init2(OPJ_CODEC_FORMAT format, unsigned char *data, int length); #endif }; @@ -140,6 +141,8 @@ void JPXStream::getImageParams(int *bitsPerComponent, StreamColorSpaceMode *csMo *bitsPerComponent = 8; if (priv->image && priv->image->numcomps == 3) *csMode = streamCSDeviceRGB; + else if (priv->image && priv->image->numcomps == 4) + *csMode = streamCSDeviceCMYK; else *csMode = streamCSDeviceGray; } @@ -225,7 +228,6 @@ void JPXStreamPrivate::init2(unsigned char *buf, int bufLen, OPJ_CODEC_FORMAT fo /* 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); @@ -260,35 +262,64 @@ error: #ifdef USE_OPENJPEG2 -static OPJ_SIZE_T readStream_callback(void *buffer, OPJ_SIZE_T nBytes, void *userData) +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; - JPXStream *p = (JPXStream *)userData; - len = p->readStream(nBytes, (Guchar*)buffer); + len = jpxData->size - jpxData->pos; + if (len < 0) + len = 0; if (len == 0) - return (OPJ_SIZE_T)-1; - else - return len; + 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; } -void JPXStream::init() +static OPJ_OFF_T jpxSkip_callback(OPJ_OFF_T skip, void * p_user_data) { - opj_stream_t *stream; + JPXData *jpxData = (JPXData *)p_user_data; - str->reset(); - stream = opj_stream_default_create(OPJ_TRUE); + 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; +} -#if OPENJPEG_VERSION >= OPENJPEG_VERSION_ENCODE(2, 1, 0) - opj_stream_set_user_data (stream, this, NULL); -#else - opj_stream_set_user_data (stream, this); -#endif +static OPJ_BOOL jpxSeek_callback(OPJ_OFF_T seek_pos, void * p_user_data) +{ + JPXData *jpxData = (JPXData *)p_user_data; - opj_stream_set_read_function(stream, readStream_callback); - priv->init2(stream, OPJ_CODEC_JP2); + if (seek_pos > jpxData->size) + return OPJ_FALSE; + jpxData->pos = seek_pos; + return OPJ_TRUE; +} - opj_stream_destroy(stream); +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); + priv->init2(OPJ_CODEC_JP2, buf, length); + gfree(buf); if (priv->image) { priv->npixels = priv->image->comps[0].w * priv->image->comps[0].h; @@ -325,8 +356,30 @@ void JPXStream::init() priv->inited = gTrue; } -void JPXStreamPrivate::init2(opj_stream_t *stream, OPJ_CODEC_FORMAT format) +void JPXStreamPrivate::init2(OPJ_CODEC_FORMAT format, unsigned char *buf, int length) { + JPXData jpxData; + + jpxData.data = buf; + jpxData.pos = 0; + jpxData.size = length; + + opj_stream_t *stream; + + stream = opj_stream_default_create(OPJ_TRUE); + +#if OPENJPEG_VERSION >= OPENJPEG_VERSION_ENCODE(2, 1, 0) + opj_stream_set_user_data (stream, &jpxData, NULL); +#else + opj_stream_set_user_data (stream, &jpxData); +#endif + + 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); + opj_codec_t *decoder; /* Use default decompression parameters */ @@ -372,17 +425,19 @@ void JPXStreamPrivate::init2(opj_stream_t *stream, OPJ_CODEC_FORMAT format) } opj_destroy_codec(decoder); + opj_stream_destroy(stream); if (image != NULL) return; error: + opj_destroy_codec(decoder); if (format == OPJ_CODEC_JP2) { error(errSyntaxWarning, -1, "Did no succeed opening JPX Stream as JP2, trying as J2K."); - init2(stream, OPJ_CODEC_J2K); + init2(OPJ_CODEC_J2K, buf, length); } 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); + init2(OPJ_CODEC_JPT, buf, length); } else { error(errSyntaxError, -1, "Did no succeed opening JPX Stream."); } commit 2841f3c34dd6366a70e4d6d307a08b3fbc3e9897 Author: Adrian Johnson <[email protected]> Date: Sun Jan 4 20:22:47 2015 +0100 Cmake support for openjpeg2 With some tweaks from Albert diff --git a/CMakeLists.txt b/CMakeLists.txt index 7fdb49a..8845d00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ option(BUILD_CPP_TESTS "Whether compile the CPP test programs." ON) option(ENABLE_SPLASH "Build the Splash graphics backend." ON) option(ENABLE_UTILS "Compile poppler command line utils." ON) option(ENABLE_CPP "Compile poppler cpp wrapper." ON) -option(ENABLE_LIBOPENJPEG "Use libopenjpeg for JPX streams." ON) +set(ENABLE_LIBOPENJPEG "auto" CACHE STRING "Use libopenjpeg for JPX streams. Possible values: auto, openjpeg1, openjpeg2. 'auto' prefers openjpeg1 over openjpeg2 if both are available. Unset to not use openjpeg.") set(ENABLE_CMS "auto" CACHE STRING "Use color management system. Possible values: auto, lcms1, lcms2. 'auto' prefers lcms2 over lcms1 if both are available. Unset to disable color management system.") option(ENABLE_LIBCURL "Build libcurl based HTTP support." OFF) option(ENABLE_ZLIB "Build with zlib (not totally safe)." OFF) @@ -151,11 +151,26 @@ if(ENABLE_ZLIB) endif(ZLIB_FOUND) set(ENABLE_ZLIB ${ZLIB_FOUND}) endif(ENABLE_ZLIB) -if(ENABLE_LIBOPENJPEG) +set(USE_OPENJPEG1 FALSE) +set(USE_OPENJPEG2 FALSE) +if(ENABLE_LIBOPENJPEG STREQUAL "auto") find_package(LIBOPENJPEG) - set(ENABLE_LIBOPENJPEG ${LIBOPENJPEG_FOUND}) - set(HAVE_OPENJPEG_H ON) -endif(ENABLE_LIBOPENJPEG) + set(USE_OPENJPEG1 ${LIBOPENJPEG_FOUND}) + set(WITH_OPENJPEG ${LIBOPENJPEG_FOUND}) + if(NOT LIBOPENJPEG_FOUND) + find_package(LIBOPENJPEG2) + set(USE_OPENJPEG2 ${LIBOPENJPEG2_FOUND}) + set(WITH_OPENJPEG ${LIBOPENJPEG2_FOUND}) + endif() +elseif(ENABLE_LIBOPENJPEG STREQUAL "openjpeg1") + find_package(LIBOPENJPEG) + set(USE_OPENJPEG1 ${LIBOPENJPEG_FOUND}) + set(WITH_OPENJPEG ${LIBOPENJPEG_FOUND}) +elseif(ENABLE_LIBOPENJPEG STREQUAL "openjpeg2") + find_package(LIBOPENJPEG2) + set(USE_OPENJPEG2 ${LIBOPENJPEG2_FOUND}) + set(WITH_OPENJPEG ${LIBOPENJPEG2_FOUND}) +endif() if(ENABLE_CMS STREQUAL "auto") find_package(LCMS2) set(USE_CMS ${LCMS2_FOUND}) @@ -225,6 +240,9 @@ endif(TIFF_FOUND) if(LIBOPENJPEG_FOUND) include_directories(${LIBOPENJPEG_INCLUDE_DIR}) endif(LIBOPENJPEG_FOUND) +if(LIBOPENJPEG2_FOUND) + include_directories(${LIBOPENJPEG2_INCLUDE_DIRS}) +endif() if(LCMS_FOUND) include_directories(${LCMS_INCLUDE_DIR}) endif(LCMS_FOUND) @@ -409,11 +427,19 @@ if(LIBOPENJPEG_FOUND) poppler/JPEG2000Stream.cc ) set(poppler_LIBS ${poppler_LIBS} ${LIBOPENJPEG_LIBRARIES}) -else (LIBOPENJPEG_FOUND) + add_definitions(-DUSE_OPENJPEG1) +elseif (LIBOPENJPEG2_FOUND) + set(poppler_SRCS ${poppler_SRCS} + poppler/JPEG2000Stream.cc + ) + add_definitions(-DUSE_OPENJPEG2) +MESSAGE(${LIBOPENJPEG2_LIBRARIES}) + set(poppler_LIBS ${poppler_LIBS} ${LIBOPENJPEG2_LIBRARIES}) +else () set(poppler_SRCS ${poppler_SRCS} poppler/JPXStream.cc ) -endif(LIBOPENJPEG_FOUND) +endif() if(USE_CMS) if(LCMS_FOUND) set(poppler_LIBS ${poppler_LIBS} ${LCMS_LIBRARIES}) @@ -574,11 +600,15 @@ if(ENABLE_XPDF_HEADERS) install(FILES poppler/JPEG2000Stream.h DESTINATION include/poppler) - else(LIBOPENJPEG_FOUND) + elseif(LIBOPENJPEG2_FOUND) + install(FILES + poppler/JPEG2000Stream.h + DESTINATION include/poppler) + else() install(FILES poppler/JPXStream.h DESTINATION include/poppler) - endif(LIBOPENJPEG_FOUND) + endif() if(ENABLE_SPLASH) install(FILES poppler/SplashOutputDev.h @@ -678,7 +708,13 @@ show_end_message_yesno("use libpng" ENABLE_LIBPNG) show_end_message_yesno("use libtiff" ENABLE_LIBTIFF) show_end_message_yesno("use zlib" ENABLE_ZLIB) show_end_message_yesno("use curl" ENABLE_LIBCURL) -show_end_message_yesno("use libopenjpeg" LIBOPENJPEG_FOUND) +show_end_message_yesno("use libopenjpeg" WITH_OPENJPEG) +if(USE_OPENJPEG1) + message(" with openjpeg1") +endif() +if(USE_OPENJPEG2) + message(" with openjpeg2") +endif() show_end_message_yesno("use cms" USE_CMS) if(LCMS_FOUND) message(" with lcms1") diff --git a/cmake/modules/FindLIBOPENJPEG2.cmake b/cmake/modules/FindLIBOPENJPEG2.cmake new file mode 100644 index 0000000..f18bd3c --- /dev/null +++ b/cmake/modules/FindLIBOPENJPEG2.cmake @@ -0,0 +1,30 @@ +# - Try to find the libopenjpeg2 library +# Once done this will define +# +# LIBOPENJPEG2_FOUND - system has libopenjpeg +# LIBOPENJPEG2_INCLUDE_DIRS - the libopenjpeg include directories +# LIBOPENJPEG2_LIBRARIES - Link these to use libopenjpeg + +# Copyright (c) 2008, Albert Astals Cid, <[email protected]> +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + + +if (LIBOPENJPEG2_LIBRARIES AND LIBOPENJPEG2_INCLUDE_DIR) + + # in cache already + set(LIBOPENJPEG2_FOUND TRUE) + +else () + + set(LIBOPENJPEG2_FOUND FALSE) + set(LIBOPENJPEG2_INCLUDE_DIRS) + set(LIBOPENJPEG2_LIBRARIES) + + find_package(PkgConfig REQUIRED) + pkg_check_modules(LIBOPENJPEG2 libopenjp2) + if (LIBOPENJPEG2_FOUND) + add_definitions(-DUSE_OPENJPEG2) + endif () +endif () commit 117af9c6bbd923954ef7de63adec8c22d51da1e4 Author: Adrian Johnson <[email protected]> Date: Sun Jan 4 19:42:34 2015 +0100 Initial attempt at libopenjpeg2 support OpenJPEG 2 has a new pkg-config name and API. - Update configure.ac to find openjpeg 2 and provide V1/v2 macros - Update JPEG2000Stream to use new API depending on openjpeg v1/v2 macros - OpenJPEG 2.1 changed the API so provide a version macro to make it easier to handle the the 2.1 change and any future changes. - Move openjpeg.h into the .cc file diff --git a/configure.ac b/configure.ac index 54dacf1..47e8aac 100644 --- a/configure.ac +++ b/configure.ac @@ -147,32 +147,57 @@ then fi -dnl Test for libopenjpeg. Versions prior to 1.4 do not provide a pkgconfig file. +dnl ##### Test for libopenjpeg. Versions prior to 1.4 do not provide a pkgconfig file. +openjpeg1="no" +openjpeg2="no" AC_ARG_ENABLE(libopenjpeg, - AC_HELP_STRING([--disable-libopenjpeg], - [Don't build against 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 ***"))]) -elif test x$enable_libopenjpeg = xtry; then + AC_HELP_STRING([--enable-libopenjpeg=@<:@auto/openjpeg1/openjpeg2/none@:>@], + [Use openjpeg for JPEG2000 images. 'auto' prefers openjpeg1 over openjpeg2 if both are available due to regressions in openjpeg2 [[default=auto]]]), + [enable_libopenjpeg=$enableval], + [enable_libopenjpeg="auto"]) + +openjpeg_header=yes + +dnl test for libopenjpeg1 +if test x$enable_libopenjpeg = xopenjpeg1 || test x$enable_libopenjpeg = xauto; 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"])]) + [openjpeg1="yes"], + [AC_CHECK_LIB([openjpeg], [opj_cio_open], + [openjpeg1="yes" + LIBOPENJPEG_LIBS="-lopenjpeg"],[openjpeg_header=no]) + AC_CHECK_HEADERS([openjpeg.h],, + [openjpeg="no"])]) +fi + +dnl test for libopenjpeg2 +if test x$openjpeg1 = xno; then + if test x$enable_libopenjpeg = xopenjpeg2 || test x$enable_libopenjpeg = xauto; then + PKG_CHECK_MODULES(LIBOPENJPEG, libopenjp2, + [openjpeg2=yes],[]) + fi fi -if test x$enable_libopenjpeg = xyes; then +if test x$enable_libopenjpeg = xopenjpeg1 && test x$openjpeg1 = xno; then + if test x$openjpeg_header = xno; then + AC_MSG_ERROR("*** libopenjpeg headers not found ***") + else + AC_MSG_ERROR("*** libopenjpeg library not found ***") + fi +fi + +if test x$enable_libopenjpeg = xopenjpeg2 && test x$openjpeg2 = xno; then + AC_MSG_ERROR("*** libopenjp2 library not found ***") +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 + AC_SUBST(LIBOPENJPEG_CFLAGS) AC_SUBST(LIBOPENJPEG_LIBS) AC_DEFINE(ENABLE_LIBOPENJPEG) @@ -182,9 +207,11 @@ if test x$enable_libopenjpeg = xyes; then [AC_DEFINE(WITH_OPENJPEG_IGNORE_PCLR_CMAP_CDEF_FLAG, 1, [OpenJPEG with the OPJ_DPARAMETERS_IGNORE_PCLR_CMAP_CDEF_FLAG flag.])], []) ]) +else + enable_libopenjpeg=no 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.]) @@ -924,6 +951,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..77a153b 100644 --- a/poppler/JPEG2000Stream.cc +++ b/poppler/JPEG2000Stream.cc @@ -6,49 +6,87 @@ // // Copyright 2008-2010, 2012 Albert Astals Cid <[email protected]> // Copyright 2011 Daniel Glöckner <[email protected]> -// Copyright 2013 Adrian Johnson <[email protected]> +// Copyright 2013,2014 Adrian Johnson <[email protected]> // // Licensed under GPLv2 or later // //======================================================================== -#include "JPEG2000Stream.h" - #include "config.h" +#include "JPEG2000Stream.h" +#include <openjpeg.h> + +#define OPENJPEG_VERSION_ENCODE(major, minor, micro) ( \ + ((major) * 10000) \ + + ((minor) * 100) \ + + ((micro) * 1)) + +#ifdef USE_OPENJPEG2 +#ifdef OPJ_VERSION_MAJOR +#define OPENJPEG_VERSION OPENJPEG_VERSION_ENCODE(OPJ_VERSION_MAJOR, OPJ_VERSION_MINOR, OPJ_VERSION_BUILD) +#else +// OpenJPEG started providing version macros in version 2.1. +// If the version macro is not found, set the version to 2.0.0 and +// assume there will be no API changes in 2.0.x. +#define OPENJPEG_VERSION OPENJPEG_VERSION_ENCODE(2, 0, 0) +#endif +#endif -JPXStream::JPXStream(Stream *strA) : FilterStream(strA) -{ - inited = gFalse; - image = NULL; - dinfo = NULL; - npixels = 0; - ncomps = 0; +struct JPXStreamPrivate { + opj_image_t *image; + int counter; + int ccounter; + int npixels; + int ncomps; + GBool inited; +#ifdef USE_OPENJPEG1 + opj_dinfo_t *dinfo; + 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 +}; + +JPXStream::JPXStream(Stream *strA) : FilterStream(strA) { + priv = new JPXStreamPrivate; + priv->inited = gFalse; + priv->image = NULL; + priv->npixels = 0; + priv->ncomps = 0; +#ifdef USE_OPENJPEG1 + priv->dinfo = NULL; +#endif } JPXStream::~JPXStream() { delete str; close(); + delete priv; } void JPXStream::reset() { - counter = 0; - ccounter = 0; + priv->counter = 0; + priv->ccounter = 0; } void JPXStream::close() { - if (image != NULL) { - opj_image_destroy(image); - image = NULL; - npixels = 0; + if (priv->image != NULL) { + opj_image_destroy(priv->image); + priv->image = NULL; + priv->npixels = 0; } - if (dinfo != NULL) { - opj_destroy_decompress(dinfo); - dinfo = NULL; + +#ifdef USE_OPENJPEG1 + if (priv->dinfo != NULL) { + opj_destroy_decompress(priv->dinfo); + priv->dinfo = NULL; } +#endif } Goffset JPXStream::getPos() { - return counter * ncomps + ccounter; + return priv->counter * priv->ncomps + priv->ccounter; } int JPXStream::getChars(int nChars, Guchar *buffer) { @@ -64,6 +102,59 @@ int JPXStream::getChar() { return doGetChar(); } +int JPXStream::doLookChar() { + if (unlikely(priv->inited == gFalse)) + init(); + + if (unlikely(priv->counter >= priv->npixels)) + return EOF; + + return ((unsigned char *)priv->image->comps[priv->ccounter].data)[priv->counter]; +} + +int JPXStream::lookChar() { + return doLookChar(); +} + +int JPXStream::doGetChar() { + int result = doLookChar(); + if (++priv->ccounter == priv->ncomps) { + priv->ccounter = 0; + ++priv->counter; + } + return result; +} + +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 (priv->inited == gFalse) + init(); + + *bitsPerComponent = 8; + if (priv->image && priv->image->numcomps == 3) + *csMode = streamCSDeviceRGB; + 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,29 +166,28 @@ 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); + priv->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) { + if (priv->image) { + priv->npixels = priv->image->comps[0].w * priv->image->comps[0].h; + priv->ncomps = priv->image->numcomps; + for (int component = 0; component < priv->ncomps; component++) { + if (priv->image->comps[component].data == NULL) { close(); break; } - unsigned char *cdata = (unsigned char *)image->comps[component].data; + unsigned char *cdata = (unsigned char *)priv->image->comps[component].data; int adjust = 0; - if (image->comps[component].prec > 8) - adjust = image->comps[component].prec - 8; + if (priv->image->comps[component].prec > 8) + adjust = priv->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]; + if (priv->image->comps[component].sgnd) + sgndcorr = 1 << (priv->image->comps[0].prec - 1); + for (int i = 0; i < priv->npixels; i++) { + int r = priv->image->comps[component].data[i]; r += sgndcorr; if (adjust) { r = (r >> adjust)+((r >> (adjust-1))%2); @@ -108,22 +198,14 @@ void JPXStream::init() } } } else - npixels = 0; + priv->npixels = 0; - counter = 0; - ccounter = 0; - inited = gTrue; + priv->counter = 0; + priv->ccounter = 0; + priv->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) +void JPXStreamPrivate::init2(unsigned char *buf, int bufLen, OPJ_CODEC_FORMAT format) { opj_cio_t *cio = NULL; @@ -174,24 +256,135 @@ error: error(errSyntaxError, -1, "Did no succeed opening JPX Stream."); } } +#endif -int JPXStream::lookChar() { - return doLookChar(); -} -GooString *JPXStream::getPSFilter(int psLevel, const char *indent) { - return NULL; +#ifdef USE_OPENJPEG2 +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; } -GBool JPXStream::isBinary(GBool last) { - return str->isBinary(gTrue); -} +void JPXStream::init() +{ + opj_stream_t *stream; -void JPXStream::getImageParams(int *bitsPerComponent, StreamColorSpaceMode *csMode) { - if (inited == gFalse) init(); + str->reset(); + stream = opj_stream_default_create(OPJ_TRUE); - *bitsPerComponent = 8; - if (image && image->numcomps == 3) *csMode = streamCSDeviceRGB; - else *csMode = streamCSDeviceGray; +#if OPENJPEG_VERSION >= OPENJPEG_VERSION_ENCODE(2, 1, 0) + opj_stream_set_user_data (stream, this, NULL); +#else + opj_stream_set_user_data (stream, this); +#endif + + opj_stream_set_read_function(stream, readStream_callback); + priv->init2(stream, OPJ_CODEC_JP2); + + opj_stream_destroy(stream); + + if (priv->image) { + priv->npixels = priv->image->comps[0].w * priv->image->comps[0].h; + priv->ncomps = priv->image->numcomps; + for (int component = 0; component < priv->ncomps; component++) { + if (priv->image->comps[component].data == NULL) { + close(); + break; + } + unsigned char *cdata = (unsigned char *)priv->image->comps[component].data; + int adjust = 0; + if (priv->image->comps[component].prec > 8) + adjust = priv->image->comps[component].prec - 8; + int sgndcorr = 0; + if (priv->image->comps[component].sgnd) + sgndcorr = 1 << (priv->image->comps[0].prec - 1); + for (int i = 0; i < priv->npixels; i++) { + int r = priv->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 { + priv->npixels = 0; + } + + priv->counter = 0; + priv->ccounter = 0; + priv->inited = gTrue; } +void JPXStreamPrivate::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."); + } +} +#endif diff --git a/poppler/JPEG2000Stream.h b/poppler/JPEG2000Stream.h index 3feccbe..50b7586 100644 --- a/poppler/JPEG2000Stream.h +++ b/poppler/JPEG2000Stream.h @@ -6,7 +6,7 @@ // // Copyright 2008, 2010 Albert Astals Cid <[email protected]> // Copyright 2011 Daniel Glöckner <[email protected]> -// Copyright 2013 Adrian Johnson <[email protected]> +// Copyright 2013,2014 Adrian Johnson <[email protected]> // // Licensed under GPLv2 or later // @@ -16,12 +16,13 @@ #ifndef JPEG2000STREAM_H #define JPEG2000STREAM_H -#include <openjpeg.h> - +#include "config.h" #include "goo/gtypes.h" #include "Object.h" #include "Stream.h" +struct JPXStreamPrivate; + class JPXStream: public FilterStream { public: @@ -37,37 +38,21 @@ 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(); - void init2(unsigned char *buf, int bufLen, OPJ_CODEC_FORMAT format); + JPXStream(const JPXStream &other); + JPXStream& operator=(const JPXStream &other); + JPXStreamPrivate *priv; + void init(); 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]; - } + int doGetChar(); - opj_image_t *image; - opj_dinfo_t *dinfo; - int counter; - int ccounter; - int npixels; - int ncomps; - GBool inited; + int doLookChar(); }; #endif
_______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
