summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2020-10-03 18:56:46 +0200
committerEven Rouault <even.rouault@spatialys.com>2020-10-16 13:40:10 +0200
commit3a2de853a932bd0ea79d1677d319841edb736c38 (patch)
tree2844d487522130af427c012d69617774cc565339
parente2801db6fd2e1bef9aec85546df68094fc24cfb3 (diff)
downloadlibtiff-git-3a2de853a932bd0ea79d1677d319841edb736c38.tar.gz
Add support for optional building against libdeflate for faster Zip/Deflate compression/decompression.
So we can have 2 kind of builds with the Zip/Deflate codec: - zlib only - zlib + libdeflate Speed improvements in the 35%-50% range can be expected when libdeflate is used. Compression level up to 12 is now supported (capped to 9 when zlib is used). Still requires zlib for situations where libdeflate cannot be used (that is for scanline access, since libdeflate has no streaming mode) Pseudo-tag TIFFTAG_DEFLATE_SUBCODEC=DEFLATE_SUBCODEC_ZLIB/DEFLATE_SUBCODEC_LIBDEFLATE is added to control which subcodec (zlib or libdeflate) should be used (it defaults of course to libdeflate, when it is available). This is mostly aimed at being used on the writing side, to be able to reproduce output of previous libtiff versions at a binary level, in situations where this would be really needed. Or as a safety belt in case there would be unforeseen issues with using libdeflate. It can be used to know when libdeflate is available at runtime (DEFLATE_SUBCODEC_LIBDEFLATE will be the default value in that situation). Of course, deflate codestreams produced by libdeflate can be read by zlib, and vice-versa.
-rw-r--r--.gitlab-ci.yml5
-rw-r--r--CMakeLists.txt34
-rw-r--r--configure.ac58
-rw-r--r--libtiff/tif_write.c4
-rw-r--r--libtiff/tif_zip.c271
-rw-r--r--libtiff/tiff.h3
-rw-r--r--libtiff/tiffconf.h.cmake.in3
-rw-r--r--libtiff/tiffconf.h.in3
-rw-r--r--man/tiffcp.111
-rw-r--r--tools/tiffcp.c17
10 files changed, 391 insertions, 18 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c8a89403..7efe145b 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,6 +1,7 @@
-image: ubuntu:16.04
+image: ubuntu:20.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 wget
+ - apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get install -y -qq autoconf automake build-essential cmake libtool libjpeg8-dev libjbig-dev liblzma-dev ninja-build zlib1g-dev libdeflate-dev zip wget
stages:
- build
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a1f964da..6669b706 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -457,6 +457,33 @@ if(ZLIB_FOUND)
set(ZLIB_SUPPORT 1)
endif()
set(ZIP_SUPPORT ${ZLIB_SUPPORT})
+
+
+# libdeflate
+option(libdeflate "use libdeflate (optional for faster Deflate support, still requires zlib)" ON)
+if (libdeflate)
+ set(DEFLATE_FOUND 0)
+ find_path(DEFLATE_INCLUDE_DIR libdeflate.h)
+ set(DEFLATE_NAMES ${DEFLATE_NAMES} libdeflate)
+ find_library(DEFLATE_LIBRARY NAMES ${DEFLATE_NAMES})
+ if (DEFLATE_INCLUDE_DIR AND DEFLATE_LIBRARY)
+ set(DEFLATE_FOUND 1)
+ set(DEFLATE_LIBRARIES ${DEFLATE_LIBRARY})
+ endif()
+endif()
+set(LIBDEFLATE_SUPPORT FALSE)
+if(DEFLATE_FOUND)
+ set(LIBDEFLATE_SUPPORT TRUE)
+endif()
+
+if(LIBDEFLATE_SUPPORT AND NOT ZIP_SUPPORT)
+ message(WARNING "libdeflate available but zlib is not. libdeflate cannot be used")
+ set(LIBDEFLATE_SUPPORT FALSE)
+endif()
+
+set(LIBDEFLATE_SUPPORT ${LIBDEFLATE_SUPPORT})
+
+
# Option for Pixar log-format algorithm
# Pixar log format
@@ -655,6 +682,9 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libtiff-4.pc
if(ZLIB_INCLUDE_DIRS)
list(APPEND TIFF_INCLUDES ${ZLIB_INCLUDE_DIRS})
endif()
+if(DEFLATE_INCLUDE_DIR)
+ list(APPEND TIFF_INCLUDES ${DEFLATE_INCLUDE_DIR})
+endif()
if(JPEG_INCLUDE_DIR)
list(APPEND TIFF_INCLUDES ${JPEG_INCLUDE_DIR})
endif()
@@ -682,6 +712,9 @@ endif()
if(ZLIB_LIBRARIES)
list(APPEND TIFF_LIBRARY_DEPS ${ZLIB_LIBRARIES})
endif()
+if(DEFLATE_LIBRARIES)
+ list(APPEND TIFF_LIBRARY_DEPS ${DEFLATE_LIBRARIES})
+endif()
if(JPEG_LIBRARIES)
list(APPEND TIFF_LIBRARY_DEPS ${JPEG_LIBRARIES})
endif()
@@ -737,6 +770,7 @@ message(STATUS " LogLuv high dynamic range encoding: ${logluv}")
message(STATUS "")
message(STATUS " Support for external codecs:")
message(STATUS " ZLIB support: ${zlib} (requested) ${ZLIB_FOUND} (availability)")
+message(STATUS " libdeflate support: ${libdeflate} (requested) ${LIBDEFLATE_SUPPORT} (availability)")
message(STATUS " Pixar log-format algorithm: ${pixarlog} (requested) ${PIXARLOG_SUPPORT} (availability)")
message(STATUS " JPEG support: ${jpeg} (requested) ${JPEG_FOUND} (availability)")
message(STATUS " Old JPEG support: ${old-jpeg} (requested) ${JPEG_FOUND} (availability)")
diff --git a/configure.ac b/configure.ac
index eecb8e99..cfba5118 100644
--- a/configure.ac
+++ b/configure.ac
@@ -615,6 +615,63 @@ if test "$HAVE_ZLIB" = "yes" ; then
fi
dnl ---------------------------------------------------------------------------
+dnl Check for libdeflate.
+dnl ---------------------------------------------------------------------------
+
+HAVE_LIBDEFLATE=no
+
+AC_ARG_ENABLE(libdeflate,
+ AS_HELP_STRING([--disable-libdeflate],
+ [disable libdeflate usage (optional for faster Deflate support (still requires zlib), enabled by default)]),,)
+AC_ARG_WITH(libdeflate-include-dir,
+ AS_HELP_STRING([--with-libdeflate-include-dir=DIR],
+ [location of libdeflate headers]),,)
+AC_ARG_WITH(libdeflate-lib-dir,
+ AS_HELP_STRING([--with-libdeflate-lib-dir=DIR],
+ [location of libdeflate library binary]),,)
+
+if test "x$enable_libdeflate" != "xno" ; then
+
+ if test "x$with_libdeflate_lib_dir" != "x" ; then
+ LDFLAGS="-L$with_libdeflate_lib_dir $LDFLAGS"
+ fi
+
+ AC_CHECK_LIB(deflate, libdeflate_zlib_decompress, [libdeflate_lib=yes], [libdeflate_lib=no],)
+ if test "$libdeflate_lib" = "no" -a "x$with_libdeflate_lib_dir" != "x"; then
+ AC_MSG_ERROR([libdeflate library not found at $with_libdeflate_lib_dir])
+ fi
+
+ if test "x$with_libdeflate_include_dir" != "x" ; then
+ CPPFLAGS="-I$with_libdeflate_include_dir $CPPFLAGS"
+ fi
+ AC_CHECK_HEADER(libdeflate.h, [libdeflate_h=yes], [libdeflate_h=no])
+ if test "$libdeflate_h" = "no" -a "x$with_libdeflate_include_dir" != "x" ; then
+ AC_MSG_ERROR([libdeflate headers not found at $with_libdeflate_include_dir])
+ fi
+
+ if test "$libdeflate_lib" = "yes" -a "$libdeflate_h" = "yes" ; then
+ HAVE_LIBDEFLATE=yes
+ fi
+
+fi
+
+if test "$HAVE_LIBDEFLATE" = "yes" -a "$HAVE_ZLIB" = "no" ; then
+ AC_MSG_WARN([libdeflate available but zlib is not. libdeflate cannot be used])
+ HAVE_LIBDEFLATE=no
+fi
+
+if test "$HAVE_LIBDEFLATE" = "yes" ; then
+ AC_DEFINE(LIBDEFLATE_SUPPORT,1,[Support libdeflate enhanced compression])
+ LIBS="-ldeflate $LIBS"
+ tiff_libs_private="-ldeflate ${tiff_libs_private}"
+
+ if test "$HAVE_RPATH" = "yes" -a "x$with_libdeflate_lib_dir" != "x" ; then
+ LIBDIR="-R $with_libdeflate_lib_dir $LIBDIR"
+ fi
+
+fi
+
+dnl ---------------------------------------------------------------------------
dnl Check for Pixar log-format algorithm.
dnl ---------------------------------------------------------------------------
@@ -1191,6 +1248,7 @@ LOC_MSG([ LogLuv high dynamic range encoding: ${HAVE_LOGLUV}])
LOC_MSG()
LOC_MSG([ Support for external codecs:])
LOC_MSG([ ZLIB support: ${HAVE_ZLIB}])
+LOC_MSG([ libdeflate support: ${HAVE_LIBDEFLATE}])
LOC_MSG([ Pixar log-format algorithm: ${HAVE_PIXARLOG}])
LOC_MSG([ JPEG support: ${HAVE_JPEG}])
LOC_MSG([ Old JPEG support: ${HAVE_OJPEG}])
diff --git a/libtiff/tif_write.c b/libtiff/tif_write.c
index f79330e9..3af69ab4 100644
--- a/libtiff/tif_write.c
+++ b/libtiff/tif_write.c
@@ -668,6 +668,10 @@ TIFFWriteBufferSetup(TIFF* tif, void* bp, tmsize_t size)
if (size == (tmsize_t)(-1)) {
size = (isTiled(tif) ?
tif->tif_tilesize : TIFFStripSize(tif));
+
+ /* Adds 10% margin for cases where compression would expand a bit */
+ if( size < TIFF_TMSIZE_T_MAX - size / 10 )
+ size += size / 10;
/*
* Make raw data buffer at least 8K
*/
diff --git a/libtiff/tif_zip.c b/libtiff/tif_zip.c
index d8fe919b..0e6e3bf3 100644
--- a/libtiff/tif_zip.c
+++ b/libtiff/tif_zip.c
@@ -29,24 +29,22 @@
*
* ZIP (aka Deflate) Compression Support
*
- * This file is simply an interface to the zlib library written by
+ * This file is an interface to the zlib library written by
* Jean-loup Gailly and Mark Adler. You must use version 1.0 or later
- * of the library: this code assumes the 1.0 API and also depends on
- * the ability to write the zlib header multiple times (one per strip)
- * which was not possible with versions prior to 0.95. Note also that
- * older versions of this codec avoided this bug by suppressing the header
- * entirely. This means that files written with the old library cannot
- * be read; they should be converted to a different compression scheme
- * and then reconverted.
+ * of the library.
*
- * The data format used by the zlib library is described in the files
- * zlib-3.1.doc, deflate-1.1.doc and gzip-4.1.doc, available in the
- * directory ftp://ftp.uu.net/pub/archiving/zip/doc. The library was
- * last found at ftp://ftp.uu.net/pub/archiving/zip/zlib/zlib-0.99.tar.gz.
+ * Optionnaly, libdeflate (https://github.com/ebiggers/libdeflate) may be used
+ * to do the compression and decompression, but only for whole strips and tiles.
+ * For scanline access, zlib will be sued as a fallback.
*/
#include "tif_predict.h"
#include "zlib.h"
+#if LIBDEFLATE_SUPPORT
+#include "libdeflate.h"
+#endif
+#define LIBDEFLATE_MAX_COMPRESSION_LEVEL 12
+
#include <stdio.h>
/*
@@ -70,6 +68,12 @@ typedef struct {
z_stream stream;
int zipquality; /* compression level */
int state; /* state flags */
+ int subcodec; /* DEFLATE_SUBCODEC_ZLIB or DEFLATE_SUBCODEC_LIBDEFLATE */
+#if LIBDEFLATE_SUPPORT
+ int libdeflate_state; /* -1 = until first time ZIPEncode() / ZIPDecode() is called, 0 = use zlib, 1 = use libdeflate */
+ struct libdeflate_decompressor* libdeflate_dec;
+ struct libdeflate_compressor* libdeflate_enc;
+#endif
#define ZSTATE_INIT_DECODE 0x01
#define ZSTATE_INIT_ENCODE 0x02
@@ -132,6 +136,9 @@ ZIPPreDecode(TIFF* tif, uint16 s)
if( (sp->state & ZSTATE_INIT_DECODE) == 0 )
tif->tif_setupdecode( tif );
+#if LIBDEFLATE_SUPPORT
+ sp->libdeflate_state = -1;
+#endif
sp->stream.next_in = tif->tif_rawdata;
assert(sizeof(sp->stream.avail_in)==4); /* if this assert gets raised,
we need to simplify this code to reflect a ZLib that is likely updated
@@ -151,6 +158,77 @@ ZIPDecode(TIFF* tif, uint8* op, tmsize_t occ, uint16 s)
assert(sp != NULL);
assert(sp->state == ZSTATE_INIT_DECODE);
+#if LIBDEFLATE_SUPPORT
+ if( sp->libdeflate_state == 1 )
+ return 0;
+
+ /* If we have libdeflate support and we are asked to read a whole */
+ /* strip/tile, then go for using it */
+ do {
+ TIFFDirectory *td = &tif->tif_dir;
+
+ if( sp->libdeflate_state == 0 )
+ break;
+ if( sp->subcodec == DEFLATE_SUBCODEC_ZLIB )
+ break;
+
+ /* Check if we are in the situation where we can use libdeflate */
+ if (isTiled(tif)) {
+ if( TIFFTileSize64(tif) != (uint64)occ )
+ break;
+ } else {
+ uint32 strip_height = td->td_imagelength - tif->tif_row;
+ if (strip_height > td->td_rowsperstrip)
+ strip_height = td->td_rowsperstrip;
+ if( TIFFVStripSize64(tif, strip_height) != (uint64)occ )
+ break;
+ }
+
+ /* Check for overflow */
+ if( (size_t)tif->tif_rawcc != (uint64)tif->tif_rawcc )
+ break;
+ if( (size_t)occ != (uint64)occ )
+ break;
+
+ /* Go for decompression using libdeflate */
+ {
+ enum libdeflate_result res;
+ if( sp->libdeflate_dec == NULL )
+ {
+ sp->libdeflate_dec = libdeflate_alloc_decompressor();
+ if( sp->libdeflate_dec == NULL )
+ {
+ break;
+ }
+ }
+
+ sp->libdeflate_state = 1;
+
+ res = libdeflate_zlib_decompress(
+ sp->libdeflate_dec, tif->tif_rawcp, (size_t)tif->tif_rawcc, op, (size_t)occ, NULL);
+
+ tif->tif_rawcp += tif->tif_rawcc;
+ tif->tif_rawcc = 0;
+
+ /* We accept LIBDEFLATE_INSUFFICIENT_SPACE has a return */
+ /* There are odd files in the wild where the last strip, when */
+ /* it is smaller in height than td_rowsperstrip, actually contains */
+ /* data for td_rowsperstrip lines. Just ignore that silently. */
+ if( res != LIBDEFLATE_SUCCESS &&
+ res != LIBDEFLATE_INSUFFICIENT_SPACE )
+ {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Decoding error at scanline %lu",
+ (unsigned long) tif->tif_row);
+ return 0;
+ }
+
+ return 1;
+ }
+ } while(0);
+ sp->libdeflate_state = 0;
+#endif /* LIBDEFLATE_SUPPORT */
+
sp->stream.next_in = tif->tif_rawcp;
sp->stream.next_out = op;
@@ -198,6 +276,7 @@ ZIPSetupEncode(TIFF* tif)
{
static const char module[] = "ZIPSetupEncode";
ZIPState* sp = EncoderState(tif);
+ int cappedQuality;
assert(sp != NULL);
if (sp->state & ZSTATE_INIT_DECODE) {
@@ -205,7 +284,11 @@ ZIPSetupEncode(TIFF* tif)
sp->state = 0;
}
- if (deflateInit(&sp->stream, sp->zipquality) != Z_OK) {
+ cappedQuality = sp->zipquality;
+ if( cappedQuality > Z_BEST_COMPRESSION )
+ cappedQuality = Z_BEST_COMPRESSION;
+
+ if (deflateInit(&sp->stream, cappedQuality) != Z_OK) {
TIFFErrorExt(tif->tif_clientdata, module, "%s", SAFE_MSG(sp));
return (0);
} else {
@@ -227,6 +310,9 @@ ZIPPreEncode(TIFF* tif, uint16 s)
if( sp->state != ZSTATE_INIT_ENCODE )
tif->tif_setupencode( tif );
+#if LIBDEFLATE_SUPPORT
+ sp->libdeflate_state = -1;
+#endif
sp->stream.next_out = tif->tif_rawdata;
assert(sizeof(sp->stream.avail_out)==4); /* if this assert gets raised,
we need to simplify this code to reflect a ZLib that is likely updated
@@ -249,6 +335,95 @@ ZIPEncode(TIFF* tif, uint8* bp, tmsize_t cc, uint16 s)
assert(sp->state == ZSTATE_INIT_ENCODE);
(void) s;
+
+#if LIBDEFLATE_SUPPORT
+ if( sp->libdeflate_state == 1 )
+ return 0;
+
+ /* If we have libdeflate support and we are asked to write a whole */
+ /* strip/tile, then go for using it */
+ do {
+ TIFFDirectory *td = &tif->tif_dir;
+
+ if( sp->libdeflate_state == 0 )
+ break;
+ if( sp->subcodec == DEFLATE_SUBCODEC_ZLIB )
+ break;
+
+ /* Libdeflate does not support the 0-compression level */
+ if( sp->zipquality == Z_NO_COMPRESSION )
+ break;
+
+ /* Check if we are in the situation where we can use libdeflate */
+ if (isTiled(tif)) {
+ if( TIFFTileSize64(tif) != (uint64)cc )
+ break;
+ } else {
+ uint32 strip_height = td->td_imagelength - tif->tif_row;
+ if (strip_height > td->td_rowsperstrip)
+ strip_height = td->td_rowsperstrip;
+ if( TIFFVStripSize64(tif, strip_height) != (uint64)cc )
+ break;
+ }
+
+ /* Check for overflow */
+ if( (size_t)tif->tif_rawdatasize != (uint64)tif->tif_rawdatasize )
+ break;
+ if( (size_t)cc != (uint64)cc )
+ break;
+
+ /* Go for compression using libdeflate */
+ {
+ size_t nCompressedBytes;
+ if( sp->libdeflate_enc == NULL )
+ {
+ /* To get results as good as zlib, we asked for an extra */
+ /* level of compression */
+ sp->libdeflate_enc = libdeflate_alloc_compressor(
+ sp->zipquality == Z_DEFAULT_COMPRESSION ? 7 :
+ sp->zipquality >= 6 && sp->zipquality <= 9 ? sp->zipquality + 1 :
+ sp->zipquality);
+ if( sp->libdeflate_enc == NULL )
+ {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Cannot allocate compressor");
+ break;
+ }
+ }
+
+ /* Make sure the output buffer is large enough for the worse case. */
+ /* In TIFFWriteBufferSetup(), when libtiff allocates the buffer */
+ /* we've taken a 10% margin over the uncompressed size, which should */
+ /* be large enough even for the the worse case scenario. */
+ if( libdeflate_zlib_compress_bound(sp->libdeflate_enc, (size_t)cc) >
+ (size_t)tif->tif_rawdatasize)
+ {
+ break;
+ }
+
+ sp->libdeflate_state = 1;
+ nCompressedBytes = libdeflate_zlib_compress(
+ sp->libdeflate_enc, bp, (size_t)cc, tif->tif_rawdata, (size_t)tif->tif_rawdatasize);
+
+ if( nCompressedBytes == 0 )
+ {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Encoder error at scanline %lu",
+ (unsigned long) tif->tif_row);
+ return 0;
+ }
+
+ tif->tif_rawcc = nCompressedBytes;
+
+ if( !TIFFFlushData1(tif) )
+ return 0;
+
+ return 1;
+ }
+ } while(0);
+ sp->libdeflate_state = 0;
+#endif /* LIBDEFLATE_SUPPORT */
+
sp->stream.next_in = bp;
assert(sizeof(sp->stream.avail_in)==4); /* if this assert gets raised,
we need to simplify this code to reflect a ZLib that is likely updated
@@ -286,6 +461,11 @@ ZIPPostEncode(TIFF* tif)
ZIPState *sp = EncoderState(tif);
int state;
+#if LIBDEFLATE_SUPPORT
+ if( sp->libdeflate_state == 1 )
+ return 1;
+#endif
+
sp->stream.avail_in = 0;
do {
state = deflate(&sp->stream, Z_FINISH);
@@ -329,6 +509,14 @@ ZIPCleanup(TIFF* tif)
inflateEnd(&sp->stream);
sp->state = 0;
}
+
+#if LIBDEFLATE_SUPPORT
+ if( sp->libdeflate_dec )
+ libdeflate_free_decompressor(sp->libdeflate_dec);
+ if( sp->libdeflate_enc )
+ libdeflate_free_compressor(sp->libdeflate_enc);
+#endif
+
_TIFFfree(sp);
tif->tif_data = NULL;
@@ -344,15 +532,55 @@ ZIPVSetField(TIFF* tif, uint32 tag, va_list ap)
switch (tag) {
case TIFFTAG_ZIPQUALITY:
sp->zipquality = (int) va_arg(ap, int);
- if ( sp->state&ZSTATE_INIT_ENCODE ) {
+ if( sp->zipquality < Z_DEFAULT_COMPRESSION ||
+ sp->zipquality > LIBDEFLATE_MAX_COMPRESSION_LEVEL ) {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Invalid ZipQuality value. Should be in [-1,%d] range",
+ LIBDEFLATE_MAX_COMPRESSION_LEVEL);
+ return 0;
+ }
+
+ if ( sp->state&ZSTATE_INIT_ENCODE ) {
+ int cappedQuality = sp->zipquality;
+ if( cappedQuality > Z_BEST_COMPRESSION )
+ cappedQuality = Z_BEST_COMPRESSION;
if (deflateParams(&sp->stream,
- sp->zipquality, Z_DEFAULT_STRATEGY) != Z_OK) {
+ cappedQuality, Z_DEFAULT_STRATEGY) != Z_OK) {
TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s",
SAFE_MSG(sp));
return (0);
}
}
+
+#if LIBDEFLATE_SUPPORT
+ if( sp->libdeflate_enc )
+ {
+ libdeflate_free_compressor(sp->libdeflate_enc);
+ sp->libdeflate_enc = NULL;
+ }
+#endif
+
return (1);
+
+ case TIFFTAG_DEFLATE_SUBCODEC:
+ sp->subcodec = (int) va_arg(ap, int);
+ if( sp->subcodec != DEFLATE_SUBCODEC_ZLIB &&
+ sp->subcodec != DEFLATE_SUBCODEC_LIBDEFLATE )
+ {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "Invalid DeflateCodec value.");
+ return 0;
+ }
+#if !LIBDEFLATE_SUPPORT
+ if( sp->subcodec == DEFLATE_SUBCODEC_LIBDEFLATE )
+ {
+ TIFFErrorExt(tif->tif_clientdata, module,
+ "DeflateCodec = DEFLATE_SUBCODEC_LIBDEFLATE unsupported in this build");
+ return 0;
+ }
+#endif
+ return 1;
+
default:
return (*sp->vsetparent)(tif, tag, ap);
}
@@ -368,6 +596,11 @@ ZIPVGetField(TIFF* tif, uint32 tag, va_list ap)
case TIFFTAG_ZIPQUALITY:
*va_arg(ap, int*) = sp->zipquality;
break;
+
+ case TIFFTAG_DEFLATE_SUBCODEC:
+ *va_arg(ap, int*) = sp->subcodec;
+ break;
+
default:
return (*sp->vgetparent)(tif, tag, ap);
}
@@ -376,6 +609,7 @@ ZIPVGetField(TIFF* tif, uint32 tag, va_list ap)
static const TIFFField zipFields[] = {
{ TIFFTAG_ZIPQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "", NULL },
+ { TIFFTAG_DEFLATE_SUBCODEC, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "", NULL },
};
int
@@ -402,7 +636,7 @@ TIFFInitZIP(TIFF* tif, int scheme)
/*
* Allocate state block so tag methods have storage to record values.
*/
- tif->tif_data = (uint8*) _TIFFmalloc(sizeof (ZIPState));
+ tif->tif_data = (uint8*) _TIFFcalloc(sizeof (ZIPState), 1);
if (tif->tif_data == NULL)
goto bad;
sp = ZState(tif);
@@ -422,6 +656,11 @@ TIFFInitZIP(TIFF* tif, int scheme)
/* Default values for codec-specific fields */
sp->zipquality = Z_DEFAULT_COMPRESSION; /* default comp. level */
sp->state = 0;
+#if LIBDEFLATE_SUPPORT
+ sp->subcodec = DEFLATE_SUBCODEC_LIBDEFLATE;
+#else
+ sp->subcodec = DEFLATE_SUBCODEC_ZLIB;
+#endif
/*
* Install codec methods.
diff --git a/libtiff/tiff.h b/libtiff/tiff.h
index def9855d..eaf392e3 100644
--- a/libtiff/tiff.h
+++ b/libtiff/tiff.h
@@ -658,6 +658,9 @@ typedef enum {
#define TIFFTAG_LERC_MAXZERROR 65567 /* LERC maximum error */
#define TIFFTAG_WEBP_LEVEL 65568 /* WebP compression level: WARNING not registered in Adobe-maintained registry */
#define TIFFTAG_WEBP_LOSSLESS 65569 /* WebP lossless/lossy : WARNING not registered in Adobe-maintained registry */
+#define TIFFTAG_DEFLATE_SUBCODEC 65570 /* ZIP codec: to get/set the sub-codec to use. Will default to libdeflate when available */
+#define DEFLATE_SUBCODEC_ZLIB 0
+#define DEFLATE_SUBCODEC_LIBDEFLATE 1
/*
* EXIF tags
diff --git a/libtiff/tiffconf.h.cmake.in b/libtiff/tiffconf.h.cmake.in
index 59542f1e..9b4b0328 100644
--- a/libtiff/tiffconf.h.cmake.in
+++ b/libtiff/tiffconf.h.cmake.in
@@ -87,6 +87,9 @@
/* Support Deflate compression */
#cmakedefine ZIP_SUPPORT 1
+/* Support libdeflate enhanced compression */
+#cmakedefine LIBDEFLATE_SUPPORT 1
+
/* Support strip chopping (whether or not to convert single-strip uncompressed
images to mutiple strips of ~8Kb to reduce memory usage) */
#cmakedefine STRIPCHOP_DEFAULT 1
diff --git a/libtiff/tiffconf.h.in b/libtiff/tiffconf.h.in
index 5de30c9b..9bd6a2de 100644
--- a/libtiff/tiffconf.h.in
+++ b/libtiff/tiffconf.h.in
@@ -84,6 +84,9 @@
/* Support Deflate compression */
#undef ZIP_SUPPORT
+/* Support libdeflate enhanced compression */
+#undef LIBDEFLATE_SUPPORT
+
/* Support strip chopping (whether or not to convert single-strip uncompressed
images to mutiple strips of ~8Kb to reduce memory usage) */
#undef STRIPCHOP_DEFAULT
diff --git a/man/tiffcp.1 b/man/tiffcp.1
index ec1875d2..6bfee348 100644
--- a/man/tiffcp.1
+++ b/man/tiffcp.1
@@ -151,6 +151,17 @@ e.g.
for
.SM Deflate
encoding with maximum compression level and floating point predictor.
+.IP
+For the
+.SM Deflate
+codec, and in a libtiff build with libdeflate enabled, ``p12`` is
+actually the maximum level.
+.IP
+For the
+.SM Deflate
+codec, and in a libtiff build with libdeflate enabled, ``s0`` can be used to
+require zlib to be used, and ``s1`` for libdeflate (defaults to libdeflate when
+it is available).
.TP
.B \-f
Specify the bit fill order to use in writing output data.
diff --git a/tools/tiffcp.c b/tools/tiffcp.c
index 9dbcf67a..e56b1c10 100644
--- a/tools/tiffcp.c
+++ b/tools/tiffcp.c
@@ -97,6 +97,7 @@ static int jpegcolormode = JPEGCOLORMODE_RGB;
static uint16 defcompression = (uint16) -1;
static uint16 defpredictor = (uint16) -1;
static int defpreset = -1;
+static int subcodec = -1;
static int tiffcp(TIFF*, TIFF*);
static int processCompressOptions(char*);
@@ -361,6 +362,8 @@ processZIPOptions(char* cp)
defpredictor = atoi(cp);
else if (*cp == 'p')
defpreset = atoi(++cp);
+ else if (*cp == 's')
+ subcodec = atoi(++cp);
else
usage(EXIT_FAILURE);
} while( (cp = strchr(cp, ':')) );
@@ -494,6 +497,9 @@ static const char* stuff[] = {
"LZW, Deflate (ZIP), LZMA2, ZSTD and WEBP options:",
" # set predictor value",
" p# set compression level (preset)",
+#if LIBDEFLATE_SUPPORT
+" s# set subcodec (0=zlib, 1=libdeflate) (only for Deflate/ZIP)",
+#endif
"For example, -c lzw:2 to get LZW-encoded data with horizontal differencing,",
"-c zip:3:p9 for Deflate encoding with maximum compression level and floating",
"point predictor.",
@@ -780,6 +786,17 @@ tiffcp(TIFF* in, TIFF* out)
TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
else
CopyField(TIFFTAG_PREDICTOR, predictor);
+ if( compression == COMPRESSION_ADOBE_DEFLATE ||
+ compression == COMPRESSION_DEFLATE )
+ {
+ if( subcodec != -1 )
+ {
+ if( TIFFSetField(out, TIFFTAG_DEFLATE_SUBCODEC, subcodec) != 1 )
+ {
+ return FALSE;
+ }
+ }
+ }
/*fallthrough*/
case COMPRESSION_WEBP:
if (preset != -1) {