summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--CMakeLists.txt28
-rw-r--r--build/gitlab-ci17
-rw-r--r--configure.ac55
-rw-r--r--libtiff/CMakeLists.txt3
-rw-r--r--libtiff/Makefile.am3
-rw-r--r--libtiff/tif_codec.c4
-rw-r--r--libtiff/tif_config.h.cmake.in3
-rw-r--r--libtiff/tif_config.h.in3
-rw-r--r--libtiff/tif_dirinfo.c4
-rw-r--r--libtiff/tif_zstd.c442
-rw-r--r--libtiff/tiff.h2
-rw-r--r--libtiff/tiffiop.h3
-rw-r--r--tools/tiffcp.c9
14 files changed, 571 insertions, 7 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 606948e4..b80f8bed 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,6 +1,6 @@
image: ubuntu:16.04
before_script:
- - apt-get update -qq && apt-get install -y -qq autoconf automake build-essential cmake libtool libjpeg8-dev libjbig-dev liblzma-dev ninja-build zlib1g-dev zip
+ - apt-get update -qq && apt-get install -y -qq autoconf automake build-essential cmake libtool libjpeg8-dev libjbig-dev liblzma-dev ninja-build zlib1g-dev zip wget
stages:
- build
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d343c711..0ee6f6a2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -522,6 +522,27 @@ if(LIBLZMA_FOUND)
set(LZMA_SUPPORT 1)
endif()
+# libzstd
+option(zstd "use libzstd (required for ZSTD compression)" ON)
+if (zstd)
+ find_path(ZSTD_INCLUDE_DIR zstd.h)
+ find_library(ZSTD_LIBRARY NAMES zstd)
+ if (ZSTD_INCLUDE_DIR AND ZSTD_LIBRARY)
+ check_library_exists ("${ZSTD_LIBRARY}" ZSTD_decompressStream "" ZSTD_RECENT_ENOUGH)
+ if (ZSTD_RECENT_ENOUGH)
+ set(ZSTD_FOUND TRUE)
+ set(ZSTD_LIBRARIES ${ZSTD_LIBRARY})
+ message(STATUS "Found ZSTD library: ${ZSTD_LIBRARY}")
+ else ()
+ message(WARNING "Found ZSTD library, but not recent enough. Use zstd >= 1.0")
+ endif ()
+ endif ()
+endif()
+set(ZSTD_SUPPORT 0)
+if(ZSTD_FOUND)
+ set(ZSTD_SUPPORT 1)
+endif()
+
# 8/12-bit jpeg mode
option(jpeg12 "enable libjpeg 8/12-bit dual mode (requires separate
12-bit libjpeg build)" ON)
@@ -632,6 +653,9 @@ endif()
if(LIBLZMA_INCLUDE_DIRS)
list(APPEND TIFF_INCLUDES ${LIBLZMA_INCLUDE_DIRS})
endif()
+if(ZSTD_INCLUDE_DIR)
+ list(APPEND TIFF_INCLUDES ${ZSTD_INCLUDE_DIR})
+endif()
# Libraries required by libtiff
set(TIFF_LIBRARY_DEPS)
@@ -653,6 +677,9 @@ endif()
if(LIBLZMA_LIBRARIES)
list(APPEND TIFF_LIBRARY_DEPS ${LIBLZMA_LIBRARIES})
endif()
+if(ZSTD_LIBRARIES)
+ list(APPEND TIFF_LIBRARY_DEPS ${ZSTD_LIBRARIES})
+endif()
#report_values(TIFF_INCLUDES TIFF_LIBRARY_DEPS)
@@ -696,6 +723,7 @@ message(STATUS " Old JPEG support: ${old-jpeg} (requested) ${
message(STATUS " JPEG 8/12 bit dual mode: ${jpeg12} (requested) ${JPEG12_FOUND} (availability)")
message(STATUS " ISO JBIG support: ${jbig} (requested) ${JBIG_FOUND} (availability)")
message(STATUS " LZMA2 support: ${lzma} (requested) ${LIBLZMA_FOUND} (availability)")
+message(STATUS " ZSTD support: ${zstd} (requested) ${ZSTD_FOUND} (availability)")
message(STATUS "")
message(STATUS " C++ support: ${cxx} (requested) ${CXX_SUPPORT} (availability)")
message(STATUS "")
diff --git a/build/gitlab-ci b/build/gitlab-ci
index 1370caec..a562f10f 100644
--- a/build/gitlab-ci
+++ b/build/gitlab-ci
@@ -13,7 +13,7 @@ autoconf_build()
mkdir autoconf-build
cd autoconf-build
echo "Running ../configure --prefix=$(pwd)/../autoconf-install) ${opts}"
- ../configure --prefix=$(pwd)/../autoconf-install ${opts}
+ ../configure --prefix=$(pwd)/../autoconf-install --with-zstd-include-dir=/tmp/include --with-zstd-lib-dir=/tmp/lib ${opts}
make
make install
make check
@@ -29,8 +29,8 @@ cmake_build()
fi
mkdir cmake-build
cd cmake-build
- echo "Running cmake -G "$1" -DCMAKE_BUILD_TYPE="$2" -DCMAKE_INSTALL_PREFIX=../autoconf-install ${opts} .."
- cmake -G "$1" -DCMAKE_BUILD_TYPE="$2" -DCMAKE_INSTALL_PREFIX=../autoconf-install ${opts} ..
+ echo "Running cmake -G "$1" -DCMAKE_BUILD_TYPE="$2" -DCMAKE_INSTALL_PREFIX=../autoconf-install -DZSTD_INCLUDE_DIR=/tmp/include -DZSTD_LIBRARY=/tmp/lib/libzstd.so ${opts} .."
+ cmake -G "$1" -DCMAKE_BUILD_TYPE="$2" -DCMAKE_INSTALL_PREFIX=../autoconf-install -DZSTD_INCLUDE_DIR=/tmp/include -DZSTD_LIBRARY=/tmp/lib/libzstd.so ${opts} ..
cmake --build .
cmake --build . --target install
ctest -V
@@ -39,6 +39,17 @@ cmake_build()
build=$1
shift
+# Build zstd
+wget https://github.com/facebook/zstd/archive/v1.3.3.tar.gz
+tar xvzf v1.3.3.tar.gz
+cd zstd-1.3.3/lib
+# Faster build
+make -j3 PREFIX=/tmp ZSTD_LEGACY_SUPPORT=0 CFLAGS=-O1
+make install PREFIX=/tmp ZSTD_LEGACY_SUPPORT=0 CFLAGS=-O1
+cd ../..
+rm -rf zstd-1.3.3
+export LD_LIBRARY_PATH=/tmp/lib
+
case $build in
autoconf)
echo "Testing Autoconf build"
diff --git a/configure.ac b/configure.ac
index e35be778..5d9e25d0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -812,6 +812,60 @@ fi
AM_CONDITIONAL(HAVE_LZMA, test "$HAVE_LZMA" = 'yes')
dnl ---------------------------------------------------------------------------
+dnl Check for libzstd.
+dnl ---------------------------------------------------------------------------
+
+HAVE_ZSTD=no
+
+AC_ARG_ENABLE(zstd,
+ AS_HELP_STRING([--disable-zstd],
+ [disable libzstd usage (required for zstd compression, enabled by default)]),,)
+AC_ARG_WITH(zstd-include-dir,
+ AS_HELP_STRING([--with-zstd-include-dir=DIR],
+ [location of libzstd headers]),,)
+AC_ARG_WITH(zstd-lib-dir,
+ AS_HELP_STRING([--with-zstd-lib-dir=DIR],
+ [location of libzstd library binary]),,)
+
+if test "x$enable_zstd" != "xno" ; then
+
+ if test "x$with_zstd_lib_dir" != "x" ; then
+ LDFLAGS="-L$with_zstd_lib_dir $LDFLAGS"
+ fi
+
+ AC_CHECK_LIB(zstd, ZSTD_decompressStream, [zstd_lib=yes], [zstd_lib=no],)
+ if test "$zstd_lib" = "no" -a "x$with_zstd_lib_dir" != "x"; then
+ AC_MSG_ERROR([zstd library not found at $with_zstd_lib_dir])
+ fi
+
+ if test "x$with_zstd_include_dir" != "x" ; then
+ CPPFLAGS="-I$with_zstd_include_dir $CPPFLAGS"
+ fi
+ AC_CHECK_HEADER(zstd.h, [zstd_h=yes], [zstd_h=no])
+ if test "$zstd_h" = "no" -a "x$with_zstd_include_dir" != "x" ; then
+ AC_MSG_ERROR([Libzstd headers not found at $with_zstd_include_dir])
+ fi
+
+ if test "$zstd_lib" = "yes" -a "$zstd_h" = "yes" ; then
+ HAVE_ZSTD=yes
+ fi
+
+fi
+
+if test "$HAVE_ZSTD" = "yes" ; then
+ AC_DEFINE(ZSTD_SUPPORT,1,[Support zstd compression])
+ LIBS="-lzstd $LIBS"
+ tiff_libs_private="-lzstd ${tiff_libs_private}"
+
+ if test "$HAVE_RPATH" = "yes" -a "x$with_zstd_lib_dir" != "x" ; then
+ LIBDIR="-R $with_zstd_lib_dir $LIBDIR"
+ fi
+
+fi
+
+AM_CONDITIONAL(HAVE_ZSTD, test "$HAVE_ZSTD" = 'yes')
+
+dnl ---------------------------------------------------------------------------
dnl Should 8/12 bit jpeg mode be enabled?
dnl ---------------------------------------------------------------------------
@@ -1088,6 +1142,7 @@ LOC_MSG([ Old JPEG support: ${HAVE_OJPEG}])
LOC_MSG([ JPEG 8/12 bit dual mode: ${HAVE_JPEG12}])
LOC_MSG([ ISO JBIG support: ${HAVE_JBIG}])
LOC_MSG([ LZMA2 support: ${HAVE_LZMA}])
+LOC_MSG([ ZSTD support: ${HAVE_ZSTD}])
LOC_MSG()
LOC_MSG([ C++ support: ${HAVE_CXX}])
LOC_MSG()
diff --git a/libtiff/CMakeLists.txt b/libtiff/CMakeLists.txt
index db2afe2a..7d97959b 100644
--- a/libtiff/CMakeLists.txt
+++ b/libtiff/CMakeLists.txt
@@ -94,7 +94,8 @@ set(tiff_SOURCES
tif_version.c
tif_warning.c
tif_write.c
- tif_zip.c)
+ tif_zip.c
+ tif_zstd.c)
set(tiffxx_HEADERS
tiffio.hxx)
diff --git a/libtiff/Makefile.am b/libtiff/Makefile.am
index 9cbc5b1d..53271e9e 100644
--- a/libtiff/Makefile.am
+++ b/libtiff/Makefile.am
@@ -99,7 +99,8 @@ libtiff_la_SOURCES = \
tif_version.c \
tif_warning.c \
tif_write.c \
- tif_zip.c
+ tif_zip.c \
+ tif_zstd.c
libtiffxx_la_SOURCES = \
tif_stream.cxx
diff --git a/libtiff/tif_codec.c b/libtiff/tif_codec.c
index e0aaacff..ac7bad85 100644
--- a/libtiff/tif_codec.c
+++ b/libtiff/tif_codec.c
@@ -70,6 +70,9 @@ static int NotConfigured(TIFF*, int);
#ifndef LZMA_SUPPORT
#define TIFFInitLZMA NotConfigured
#endif
+#ifndef ZSTD_SUPPORT
+#define TIFFInitZSTD NotConfigured
+#endif
/*
* Compression schemes statically built into the library.
@@ -97,6 +100,7 @@ TIFFCodec _TIFFBuiltinCODECS[] = {
{ "SGILog", COMPRESSION_SGILOG, TIFFInitSGILog },
{ "SGILog24", COMPRESSION_SGILOG24, TIFFInitSGILog },
{ "LZMA", COMPRESSION_LZMA, TIFFInitLZMA },
+ { "ZSTD", COMPRESSION_ZSTD, TIFFInitZSTD },
{ NULL, 0, NULL }
};
diff --git a/libtiff/tif_config.h.cmake.in b/libtiff/tif_config.h.cmake.in
index e54fda88..cbbcf825 100644
--- a/libtiff/tif_config.h.cmake.in
+++ b/libtiff/tif_config.h.cmake.in
@@ -104,6 +104,9 @@
/* Support LZMA2 compression */
#cmakedefine LZMA_SUPPORT 1
+/* Support ZSTD compression */
+#cmakedefine ZSTD_SUPPORT 1
+
/* Name of package */
#define PACKAGE "@PACKAGE_NAME@"
diff --git a/libtiff/tif_config.h.in b/libtiff/tif_config.h.in
index 3db8077f..789150db 100644
--- a/libtiff/tif_config.h.in
+++ b/libtiff/tif_config.h.in
@@ -320,6 +320,9 @@
/* Support Deflate compression */
#undef ZIP_SUPPORT
+/* Support zstd compression */
+#undef ZSTD_SUPPORT
+
/* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1
diff --git a/libtiff/tif_dirinfo.c b/libtiff/tif_dirinfo.c
index d26fd120..fd12b737 100644
--- a/libtiff/tif_dirinfo.c
+++ b/libtiff/tif_dirinfo.c
@@ -1052,6 +1052,10 @@ _TIFFCheckFieldIsValidForCodec(TIFF *tif, ttag_t tag)
if (tag == TIFFTAG_PREDICTOR)
return 1;
break;
+ case COMPRESSION_ZSTD:
+ if (tag == TIFFTAG_PREDICTOR)
+ return 1;
+ break;
}
return 0;
diff --git a/libtiff/tif_zstd.c b/libtiff/tif_zstd.c
new file mode 100644
index 00000000..2bdf1129
--- /dev/null
+++ b/libtiff/tif_zstd.c
@@ -0,0 +1,442 @@
+/*
+* Copyright (c) 2017, Planet Labs
+* Author: <even.rouault at spatialys.com>
+*
+* Permission to use, copy, modify, distribute, and sell this software and
+* its documentation for any purpose is hereby granted without fee, provided
+* that (i) the above copyright notices and this permission notice appear in
+* all copies of the software and related documentation, and (ii) the names of
+* Sam Leffler and Silicon Graphics may not be used in any advertising or
+* publicity relating to the software without the specific, prior written
+* permission of Sam Leffler and Silicon Graphics.
+*
+* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+*
+* IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
+* ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
+* OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+* WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
+* LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+* OF THIS SOFTWARE.
+*/
+
+#include "tiffiop.h"
+#ifdef ZSTD_SUPPORT
+/*
+* TIFF Library.
+*
+* ZSTD Compression Support
+*
+*/
+
+#include "tif_predict.h"
+#include "zstd.h"
+
+#include <stdio.h>
+
+/*
+* State block for each open TIFF file using ZSTD compression/decompression.
+*/
+typedef struct {
+ TIFFPredictorState predict;
+ ZSTD_DStream* dstream;
+ ZSTD_CStream* cstream;
+ int compression_level; /* compression level */
+ ZSTD_outBuffer out_buffer;
+ int state; /* state flags */
+#define LSTATE_INIT_DECODE 0x01
+#define LSTATE_INIT_ENCODE 0x02
+
+ TIFFVGetMethod vgetparent; /* super-class method */
+ TIFFVSetMethod vsetparent; /* super-class method */
+} ZSTDState;
+
+#define LState(tif) ((ZSTDState*) (tif)->tif_data)
+#define DecoderState(tif) LState(tif)
+#define EncoderState(tif) LState(tif)
+
+static int ZSTDEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s);
+static int ZSTDDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s);
+
+static int
+ZSTDFixupTags(TIFF* tif)
+{
+ (void) tif;
+ return 1;
+}
+
+static int
+ZSTDSetupDecode(TIFF* tif)
+{
+ ZSTDState* sp = DecoderState(tif);
+
+ assert(sp != NULL);
+
+ /* if we were last encoding, terminate this mode */
+ if (sp->state & LSTATE_INIT_ENCODE) {
+ ZSTD_freeCStream(sp->cstream);
+ sp->cstream = NULL;
+ sp->state = 0;
+ }
+
+ sp->state |= LSTATE_INIT_DECODE;
+ return 1;
+}
+
+/*
+* Setup state for decoding a strip.
+*/
+static int
+ZSTDPreDecode(TIFF* tif, uint16 s)
+{
+ static const char module[] = "ZSTDPreDecode";
+ ZSTDState* sp = DecoderState(tif);
+ size_t zstd_ret;
+
+ (void) s;
+ assert(sp != NULL);
+
+ if( (sp->state & LSTATE_INIT_DECODE) == 0 )
+ tif->tif_setupdecode(tif);
+
+ if( sp->dstream )
+ {
+ ZSTD_freeDStream(sp->dstream);
+ sp->dstream = NULL;
+ }
+
+ sp->dstream = ZSTD_createDStream();
+ if( sp->dstream == NULL ) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Cannot allocate decompression stream");
+ return 0;
+ }
+ zstd_ret = ZSTD_initDStream(sp->dstream);
+ if( ZSTD_isError(zstd_ret) ) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Error in ZSTD_initDStream(): %s",
+ ZSTD_getErrorName(zstd_ret));
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+ZSTDDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
+{
+ static const char module[] = "ZSTDDecode";
+ ZSTDState* sp = DecoderState(tif);
+ ZSTD_inBuffer in_buffer;
+ ZSTD_outBuffer out_buffer;
+ size_t zstd_ret;
+
+ (void) s;
+ assert(sp != NULL);
+ assert(sp->state == LSTATE_INIT_DECODE);
+
+ in_buffer.src = tif->tif_rawcp;
+ in_buffer.size = (size_t) tif->tif_rawcc;
+ in_buffer.pos = 0;
+
+ out_buffer.dst = op;
+ out_buffer.size = (size_t) occ;
+ out_buffer.pos = 0;
+
+ do {
+ zstd_ret = ZSTD_decompressStream(sp->dstream, &out_buffer,
+ &in_buffer);
+ if( ZSTD_isError(zstd_ret) ) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Error in ZSTD_decompressStream(): %s",
+ ZSTD_getErrorName(zstd_ret));
+ return 0;
+ }
+ } while( zstd_ret != 0 &&
+ in_buffer.pos < in_buffer.size &&
+ out_buffer.pos < out_buffer.size );
+
+ if (out_buffer.pos < (size_t)occ) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Not enough data at scanline %lu (short %lu bytes)",
+ (unsigned long) tif->tif_row,
+ (unsigned long) (size_t)occ - out_buffer.pos);
+ return 0;
+ }
+
+ tif->tif_rawcp += in_buffer.pos;
+ tif->tif_rawcc -= in_buffer.pos;
+
+ return 1;
+}
+
+static int
+ZSTDSetupEncode(TIFF* tif)
+{
+ ZSTDState* sp = EncoderState(tif);
+
+ assert(sp != NULL);
+ if (sp->state & LSTATE_INIT_DECODE) {
+ ZSTD_freeDStream(sp->dstream);
+ sp->dstream = NULL;
+ sp->state = 0;
+ }
+
+ sp->state |= LSTATE_INIT_ENCODE;
+ return 1;
+}
+
+/*
+* Reset encoding state at the start of a strip.
+*/
+static int
+ZSTDPreEncode(TIFF* tif, uint16 s)
+{
+ static const char module[] = "ZSTDPreEncode";
+ ZSTDState *sp = EncoderState(tif);
+ size_t zstd_ret;
+
+ (void) s;
+ assert(sp != NULL);
+ if( sp->state != LSTATE_INIT_ENCODE )
+ tif->tif_setupencode(tif);
+
+ if (sp->cstream) {
+ ZSTD_freeCStream(sp->cstream);
+ sp->cstream = NULL;
+ }
+ sp->cstream = ZSTD_createCStream();
+ if( sp->cstream == NULL ) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Cannot allocate compression stream");
+ return 0;
+ }
+
+ zstd_ret = ZSTD_initCStream(sp->cstream, sp->compression_level);
+ if( ZSTD_isError(zstd_ret) ) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Error in ZSTD_initCStream(): %s",
+ ZSTD_getErrorName(zstd_ret));
+ return 0;
+ }
+
+ sp->out_buffer.dst = tif->tif_rawdata;
+ sp->out_buffer.size = (size_t)tif->tif_rawdatasize;
+ sp->out_buffer.pos = 0;
+
+ return 1;
+}
+
+/*
+* Encode a chunk of pixels.
+*/
+static int
+ZSTDEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
+{
+ static const char module[] = "ZSTDEncode";
+ ZSTDState *sp = EncoderState(tif);
+ ZSTD_inBuffer in_buffer;
+ size_t zstd_ret;
+
+ assert(sp != NULL);
+ assert(sp->state == LSTATE_INIT_ENCODE);
+
+ (void) s;
+
+ in_buffer.src = bp;
+ in_buffer.size = (size_t)cc;
+ in_buffer.pos = 0;
+
+ do {
+ zstd_ret = ZSTD_compressStream(sp->cstream, &sp->out_buffer,
+ &in_buffer);
+ if( ZSTD_isError(zstd_ret) ) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Error in ZSTD_compressStream(): %s",
+ ZSTD_getErrorName(zstd_ret));
+ return 0;
+ }
+ if( sp->out_buffer.pos == sp->out_buffer.size ) {
+ tif->tif_rawcc = tif->tif_rawdatasize;
+ TIFFFlushData1(tif);
+ sp->out_buffer.dst = tif->tif_rawcp;
+ sp->out_buffer.size = (size_t) tif->tif_rawcc;
+ sp->out_buffer.pos = 0;
+ }
+ } while( in_buffer.pos < in_buffer.size );
+
+ return 1;
+}
+
+/*
+* Finish off an encoded strip by flushing it.
+*/
+static int
+ZSTDPostEncode(TIFF* tif)
+{
+ static const char module[] = "ZSTDPostEncode";
+ ZSTDState *sp = EncoderState(tif);
+ size_t zstd_ret;
+
+ do {
+ zstd_ret = ZSTD_endStream(sp->cstream, &sp->out_buffer);
+ if( ZSTD_isError(zstd_ret) ) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Error in ZSTD_endStream(): %s",
+ ZSTD_getErrorName(zstd_ret));
+ return 0;
+ }
+ if( sp->out_buffer.pos > 0 ) {
+ tif->tif_rawcc = sp->out_buffer.pos;
+ TIFFFlushData1(tif);
+ sp->out_buffer.dst = tif->tif_rawcp;
+ sp->out_buffer.size = (size_t) tif->tif_rawcc;
+ sp->out_buffer.pos = 0;
+ }
+ } while (zstd_ret != 0);
+ return 1;
+}
+
+static void
+ZSTDCleanup(TIFF* tif)
+{
+ ZSTDState* sp = LState(tif);
+
+ assert(sp != 0);
+
+ (void)TIFFPredictorCleanup(tif);
+
+ tif->tif_tagmethods.vgetfield = sp->vgetparent;
+ tif->tif_tagmethods.vsetfield = sp->vsetparent;
+
+ if (sp->dstream) {
+ ZSTD_freeDStream(sp->dstream);
+ sp->dstream = NULL;
+ }
+ if (sp->cstream) {
+ ZSTD_freeCStream(sp->cstream);
+ sp->cstream = NULL;
+ }
+ _TIFFfree(sp);
+ tif->tif_data = NULL;
+
+ _TIFFSetDefaultCompressionState(tif);
+}
+
+static int
+ZSTDVSetField(TIFF* tif, uint32 tag, va_list ap)
+{
+ static const char module[] = "ZSTDVSetField";
+ ZSTDState* sp = LState(tif);
+
+ switch (tag) {
+ case TIFFTAG_ZSTD_LEVEL:
+ sp->compression_level = (int) va_arg(ap, int);
+ if( sp->compression_level <= 0 ||
+ sp->compression_level > ZSTD_maxCLevel() )
+ {
+ TIFFWarningExt(tif->tif_clientdata, module,
+ "ZSTD_LEVEL should be between 1 and %d",
+ ZSTD_maxCLevel());
+ }
+ return 1;
+ default:
+ return (*sp->vsetparent)(tif, tag, ap);
+ }
+ /*NOTREACHED*/
+}
+
+static int
+ZSTDVGetField(TIFF* tif, uint32 tag, va_list ap)
+{
+ ZSTDState* sp = LState(tif);
+
+ switch (tag) {
+ case TIFFTAG_ZSTD_LEVEL:
+ *va_arg(ap, int*) = sp->compression_level;
+ break;
+ default:
+ return (*sp->vgetparent)(tif, tag, ap);
+ }
+ return 1;
+}
+
+static const TIFFField ZSTDFields[] = {
+ { TIFFTAG_ZSTD_LEVEL, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT,
+ TIFF_SETGET_UNDEFINED,
+ FIELD_PSEUDO, TRUE, FALSE, "ZSTD compression_level", NULL },
+};
+
+int
+TIFFInitZSTD(TIFF* tif, int scheme)
+{
+ static const char module[] = "TIFFInitZSTD";
+ ZSTDState* sp;
+
+ assert( scheme == COMPRESSION_ZSTD );
+
+ /*
+ * Merge codec-specific tag information.
+ */
+ if (!_TIFFMergeFields(tif, ZSTDFields, TIFFArrayCount(ZSTDFields))) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Merging ZSTD codec-specific tags failed");
+ return 0;
+ }
+
+ /*
+ * Allocate state block so tag methods have storage to record values.
+ */
+ tif->tif_data = (uint8*) _TIFFmalloc(sizeof(ZSTDState));
+ if (tif->tif_data == NULL)
+ goto bad;
+ sp = LState(tif);
+
+ /*
+ * Override parent get/set field methods.
+ */
+ sp->vgetparent = tif->tif_tagmethods.vgetfield;
+ tif->tif_tagmethods.vgetfield = ZSTDVGetField; /* hook for codec tags */
+ sp->vsetparent = tif->tif_tagmethods.vsetfield;
+ tif->tif_tagmethods.vsetfield = ZSTDVSetField; /* hook for codec tags */
+
+ /* Default values for codec-specific fields */
+ sp->compression_level = 9; /* default comp. level */
+ sp->state = 0;
+ sp->dstream = 0;
+ sp->cstream = 0;
+ sp->out_buffer.dst = NULL;
+ sp->out_buffer.size = 0;
+ sp->out_buffer.pos = 0;
+
+ /*
+ * Install codec methods.
+ */
+ tif->tif_fixuptags = ZSTDFixupTags;
+ tif->tif_setupdecode = ZSTDSetupDecode;
+ tif->tif_predecode = ZSTDPreDecode;
+ tif->tif_decoderow = ZSTDDecode;
+ tif->tif_decodestrip = ZSTDDecode;
+ tif->tif_decodetile = ZSTDDecode;
+ tif->tif_setupencode = ZSTDSetupEncode;
+ tif->tif_preencode = ZSTDPreEncode;
+ tif->tif_postencode = ZSTDPostEncode;
+ tif->tif_encoderow = ZSTDEncode;
+ tif->tif_encodestrip = ZSTDEncode;
+ tif->tif_encodetile = ZSTDEncode;
+ tif->tif_cleanup = ZSTDCleanup;
+ /*
+ * Setup predictor setup.
+ */
+ (void) TIFFPredictorInit(tif);
+ return 1;
+bad:
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "No space for ZSTD state block");
+ return 0;
+}
+#endif /* ZSTD_SUPPORT */
+
+/* vim: set ts=8 sts=8 sw=8 noet: */
diff --git a/libtiff/tiff.h b/libtiff/tiff.h
index 51c0a44c..4c2f5adc 100644
--- a/libtiff/tiff.h
+++ b/libtiff/tiff.h
@@ -188,6 +188,7 @@ typedef enum {
#define COMPRESSION_SGILOG24 34677 /* SGI Log 24-bit packed */
#define COMPRESSION_JP2000 34712 /* Leadtools JPEG2000 */
#define COMPRESSION_LZMA 34925 /* LZMA2 */
+#define COMPRESSION_ZSTD 34926 /* ZSTD: WARNING not registerd in Adobe-maintained registry */
#define TIFFTAG_PHOTOMETRIC 262 /* photometric interpretation */
#define PHOTOMETRIC_MINISWHITE 0 /* min value is white */
#define PHOTOMETRIC_MINISBLACK 1 /* min value is black */
@@ -601,6 +602,7 @@ typedef enum {
#define TIFFTAG_PERSAMPLE 65563 /* interface for per sample tags */
#define PERSAMPLE_MERGED 0 /* present as a single value */
#define PERSAMPLE_MULTI 1 /* present as multiple values */
+#define TIFFTAG_ZSTD_LEVEL 65534 /* ZSTD compression level */
/*
* EXIF tags
diff --git a/libtiff/tiffiop.h b/libtiff/tiffiop.h
index 897b9e64..b4c84a2a 100644
--- a/libtiff/tiffiop.h
+++ b/libtiff/tiffiop.h
@@ -426,6 +426,9 @@ extern int TIFFInitSGILog(TIFF*, int);
#ifdef LZMA_SUPPORT
extern int TIFFInitLZMA(TIFF*, int);
#endif
+#ifdef ZSTD_SUPPORT
+extern int TIFFInitZSTD(TIFF*, int);
+#endif
#ifdef VMS
extern const TIFFCodec _TIFFBuiltinCODECS[];
#else
diff --git a/tools/tiffcp.c b/tools/tiffcp.c
index 08df56d5..482f5f4f 100644
--- a/tools/tiffcp.c
+++ b/tools/tiffcp.c
@@ -389,6 +389,9 @@ processCompressOptions(char* opt)
} else if (strneq(opt, "lzma", 4)) {
processZIPOptions(opt);
defcompression = COMPRESSION_LZMA;
+ } else if (strneq(opt, "zstd", 4)) {
+ processZIPOptions(opt);
+ defcompression = COMPRESSION_ZSTD;
} else if (strneq(opt, "jbig", 4)) {
defcompression = COMPRESSION_JBIG;
} else if (strneq(opt, "sgilog", 6)) {
@@ -427,6 +430,7 @@ char* stuff[] = {
" -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
" -c zip[:opts] compress output with deflate encoding",
" -c lzma[:opts] compress output with LZMA2 encoding",
+" -c zstd[:opts] compress output with ZSTD encoding",
" -c jpeg[:opts] compress output with JPEG encoding",
" -c jbig compress output with ISO JBIG encoding",
" -c packbits compress output with packbits encoding",
@@ -446,7 +450,7 @@ char* stuff[] = {
" r output color image as RGB rather than YCbCr",
"For example, -c jpeg:r:50 to get JPEG-encoded RGB data with 50% comp. quality",
"",
-"LZW, Deflate (ZIP) and LZMA2 options:",
+"LZW, Deflate (ZIP), LZMA2 and ZSTD options:",
" # set predictor value",
" p# set compression level (preset)",
"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing,",
@@ -731,6 +735,7 @@ tiffcp(TIFF* in, TIFF* out)
case COMPRESSION_ADOBE_DEFLATE:
case COMPRESSION_DEFLATE:
case COMPRESSION_LZMA:
+ case COMPRESSION_ZSTD:
if (predictor != (uint16)-1)
TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
else
@@ -741,6 +746,8 @@ tiffcp(TIFF* in, TIFF* out)
TIFFSetField(out, TIFFTAG_ZIPQUALITY, preset);
else if (compression == COMPRESSION_LZMA)
TIFFSetField(out, TIFFTAG_LZMAPRESET, preset);
+ else if (compression == COMPRESSION_ZSTD)
+ TIFFSetField(out, TIFFTAG_ZSTD_LEVEL, preset);
}
break;
case COMPRESSION_CCITTFAX3: