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.
This commit is contained in:
Even Rouault 2020-10-03 18:56:46 +02:00
parent e2801db6fd
commit 3a2de853a9
No known key found for this signature in database
GPG Key ID: 33EBBFC47B3DD87D
10 changed files with 391 additions and 18 deletions

View File

@ -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

View File

@ -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)")

View File

@ -614,6 +614,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}])

View File

@ -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
*/

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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) {