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:
parent
e2801db6fd
commit
3a2de853a9
@ -1,6 +1,7 @@
|
|||||||
image: ubuntu:16.04
|
image: ubuntu:20.04
|
||||||
|
|
||||||
before_script:
|
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:
|
stages:
|
||||||
- build
|
- build
|
||||||
|
@ -457,6 +457,33 @@ if(ZLIB_FOUND)
|
|||||||
set(ZLIB_SUPPORT 1)
|
set(ZLIB_SUPPORT 1)
|
||||||
endif()
|
endif()
|
||||||
set(ZIP_SUPPORT ${ZLIB_SUPPORT})
|
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
|
# Option for Pixar log-format algorithm
|
||||||
|
|
||||||
# Pixar log format
|
# Pixar log format
|
||||||
@ -655,6 +682,9 @@ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libtiff-4.pc
|
|||||||
if(ZLIB_INCLUDE_DIRS)
|
if(ZLIB_INCLUDE_DIRS)
|
||||||
list(APPEND TIFF_INCLUDES ${ZLIB_INCLUDE_DIRS})
|
list(APPEND TIFF_INCLUDES ${ZLIB_INCLUDE_DIRS})
|
||||||
endif()
|
endif()
|
||||||
|
if(DEFLATE_INCLUDE_DIR)
|
||||||
|
list(APPEND TIFF_INCLUDES ${DEFLATE_INCLUDE_DIR})
|
||||||
|
endif()
|
||||||
if(JPEG_INCLUDE_DIR)
|
if(JPEG_INCLUDE_DIR)
|
||||||
list(APPEND TIFF_INCLUDES ${JPEG_INCLUDE_DIR})
|
list(APPEND TIFF_INCLUDES ${JPEG_INCLUDE_DIR})
|
||||||
endif()
|
endif()
|
||||||
@ -682,6 +712,9 @@ endif()
|
|||||||
if(ZLIB_LIBRARIES)
|
if(ZLIB_LIBRARIES)
|
||||||
list(APPEND TIFF_LIBRARY_DEPS ${ZLIB_LIBRARIES})
|
list(APPEND TIFF_LIBRARY_DEPS ${ZLIB_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
|
if(DEFLATE_LIBRARIES)
|
||||||
|
list(APPEND TIFF_LIBRARY_DEPS ${DEFLATE_LIBRARIES})
|
||||||
|
endif()
|
||||||
if(JPEG_LIBRARIES)
|
if(JPEG_LIBRARIES)
|
||||||
list(APPEND TIFF_LIBRARY_DEPS ${JPEG_LIBRARIES})
|
list(APPEND TIFF_LIBRARY_DEPS ${JPEG_LIBRARIES})
|
||||||
endif()
|
endif()
|
||||||
@ -737,6 +770,7 @@ message(STATUS " LogLuv high dynamic range encoding: ${logluv}")
|
|||||||
message(STATUS "")
|
message(STATUS "")
|
||||||
message(STATUS " Support for external codecs:")
|
message(STATUS " Support for external codecs:")
|
||||||
message(STATUS " ZLIB support: ${zlib} (requested) ${ZLIB_FOUND} (availability)")
|
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 " Pixar log-format algorithm: ${pixarlog} (requested) ${PIXARLOG_SUPPORT} (availability)")
|
||||||
message(STATUS " JPEG support: ${jpeg} (requested) ${JPEG_FOUND} (availability)")
|
message(STATUS " JPEG support: ${jpeg} (requested) ${JPEG_FOUND} (availability)")
|
||||||
message(STATUS " Old JPEG support: ${old-jpeg} (requested) ${JPEG_FOUND} (availability)")
|
message(STATUS " Old JPEG support: ${old-jpeg} (requested) ${JPEG_FOUND} (availability)")
|
||||||
|
58
configure.ac
58
configure.ac
@ -614,6 +614,63 @@ if test "$HAVE_ZLIB" = "yes" ; then
|
|||||||
|
|
||||||
fi
|
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 ---------------------------------------------------------------------------
|
||||||
dnl Check for Pixar log-format algorithm.
|
dnl Check for Pixar log-format algorithm.
|
||||||
dnl ---------------------------------------------------------------------------
|
dnl ---------------------------------------------------------------------------
|
||||||
@ -1191,6 +1248,7 @@ LOC_MSG([ LogLuv high dynamic range encoding: ${HAVE_LOGLUV}])
|
|||||||
LOC_MSG()
|
LOC_MSG()
|
||||||
LOC_MSG([ Support for external codecs:])
|
LOC_MSG([ Support for external codecs:])
|
||||||
LOC_MSG([ ZLIB support: ${HAVE_ZLIB}])
|
LOC_MSG([ ZLIB support: ${HAVE_ZLIB}])
|
||||||
|
LOC_MSG([ libdeflate support: ${HAVE_LIBDEFLATE}])
|
||||||
LOC_MSG([ Pixar log-format algorithm: ${HAVE_PIXARLOG}])
|
LOC_MSG([ Pixar log-format algorithm: ${HAVE_PIXARLOG}])
|
||||||
LOC_MSG([ JPEG support: ${HAVE_JPEG}])
|
LOC_MSG([ JPEG support: ${HAVE_JPEG}])
|
||||||
LOC_MSG([ Old JPEG support: ${HAVE_OJPEG}])
|
LOC_MSG([ Old JPEG support: ${HAVE_OJPEG}])
|
||||||
|
@ -668,6 +668,10 @@ TIFFWriteBufferSetup(TIFF* tif, void* bp, tmsize_t size)
|
|||||||
if (size == (tmsize_t)(-1)) {
|
if (size == (tmsize_t)(-1)) {
|
||||||
size = (isTiled(tif) ?
|
size = (isTiled(tif) ?
|
||||||
tif->tif_tilesize : TIFFStripSize(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
|
* Make raw data buffer at least 8K
|
||||||
*/
|
*/
|
||||||
|
@ -29,24 +29,22 @@
|
|||||||
*
|
*
|
||||||
* ZIP (aka Deflate) Compression Support
|
* 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
|
* 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
|
* of the library.
|
||||||
* 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.
|
|
||||||
*
|
*
|
||||||
* The data format used by the zlib library is described in the files
|
* Optionnaly, libdeflate (https://github.com/ebiggers/libdeflate) may be used
|
||||||
* zlib-3.1.doc, deflate-1.1.doc and gzip-4.1.doc, available in the
|
* to do the compression and decompression, but only for whole strips and tiles.
|
||||||
* directory ftp://ftp.uu.net/pub/archiving/zip/doc. The library was
|
* For scanline access, zlib will be sued as a fallback.
|
||||||
* last found at ftp://ftp.uu.net/pub/archiving/zip/zlib/zlib-0.99.tar.gz.
|
|
||||||
*/
|
*/
|
||||||
#include "tif_predict.h"
|
#include "tif_predict.h"
|
||||||
#include "zlib.h"
|
#include "zlib.h"
|
||||||
|
|
||||||
|
#if LIBDEFLATE_SUPPORT
|
||||||
|
#include "libdeflate.h"
|
||||||
|
#endif
|
||||||
|
#define LIBDEFLATE_MAX_COMPRESSION_LEVEL 12
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -70,6 +68,12 @@ typedef struct {
|
|||||||
z_stream stream;
|
z_stream stream;
|
||||||
int zipquality; /* compression level */
|
int zipquality; /* compression level */
|
||||||
int state; /* state flags */
|
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_DECODE 0x01
|
||||||
#define ZSTATE_INIT_ENCODE 0x02
|
#define ZSTATE_INIT_ENCODE 0x02
|
||||||
|
|
||||||
@ -132,6 +136,9 @@ ZIPPreDecode(TIFF* tif, uint16 s)
|
|||||||
if( (sp->state & ZSTATE_INIT_DECODE) == 0 )
|
if( (sp->state & ZSTATE_INIT_DECODE) == 0 )
|
||||||
tif->tif_setupdecode( tif );
|
tif->tif_setupdecode( tif );
|
||||||
|
|
||||||
|
#if LIBDEFLATE_SUPPORT
|
||||||
|
sp->libdeflate_state = -1;
|
||||||
|
#endif
|
||||||
sp->stream.next_in = tif->tif_rawdata;
|
sp->stream.next_in = tif->tif_rawdata;
|
||||||
assert(sizeof(sp->stream.avail_in)==4); /* if this assert gets raised,
|
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
|
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 != NULL);
|
||||||
assert(sp->state == ZSTATE_INIT_DECODE);
|
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_in = tif->tif_rawcp;
|
||||||
|
|
||||||
sp->stream.next_out = op;
|
sp->stream.next_out = op;
|
||||||
@ -198,6 +276,7 @@ ZIPSetupEncode(TIFF* tif)
|
|||||||
{
|
{
|
||||||
static const char module[] = "ZIPSetupEncode";
|
static const char module[] = "ZIPSetupEncode";
|
||||||
ZIPState* sp = EncoderState(tif);
|
ZIPState* sp = EncoderState(tif);
|
||||||
|
int cappedQuality;
|
||||||
|
|
||||||
assert(sp != NULL);
|
assert(sp != NULL);
|
||||||
if (sp->state & ZSTATE_INIT_DECODE) {
|
if (sp->state & ZSTATE_INIT_DECODE) {
|
||||||
@ -205,7 +284,11 @@ ZIPSetupEncode(TIFF* tif)
|
|||||||
sp->state = 0;
|
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));
|
TIFFErrorExt(tif->tif_clientdata, module, "%s", SAFE_MSG(sp));
|
||||||
return (0);
|
return (0);
|
||||||
} else {
|
} else {
|
||||||
@ -227,6 +310,9 @@ ZIPPreEncode(TIFF* tif, uint16 s)
|
|||||||
if( sp->state != ZSTATE_INIT_ENCODE )
|
if( sp->state != ZSTATE_INIT_ENCODE )
|
||||||
tif->tif_setupencode( tif );
|
tif->tif_setupencode( tif );
|
||||||
|
|
||||||
|
#if LIBDEFLATE_SUPPORT
|
||||||
|
sp->libdeflate_state = -1;
|
||||||
|
#endif
|
||||||
sp->stream.next_out = tif->tif_rawdata;
|
sp->stream.next_out = tif->tif_rawdata;
|
||||||
assert(sizeof(sp->stream.avail_out)==4); /* if this assert gets raised,
|
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
|
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);
|
assert(sp->state == ZSTATE_INIT_ENCODE);
|
||||||
|
|
||||||
(void) s;
|
(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;
|
sp->stream.next_in = bp;
|
||||||
assert(sizeof(sp->stream.avail_in)==4); /* if this assert gets raised,
|
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
|
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);
|
ZIPState *sp = EncoderState(tif);
|
||||||
int state;
|
int state;
|
||||||
|
|
||||||
|
#if LIBDEFLATE_SUPPORT
|
||||||
|
if( sp->libdeflate_state == 1 )
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
sp->stream.avail_in = 0;
|
sp->stream.avail_in = 0;
|
||||||
do {
|
do {
|
||||||
state = deflate(&sp->stream, Z_FINISH);
|
state = deflate(&sp->stream, Z_FINISH);
|
||||||
@ -329,6 +509,14 @@ ZIPCleanup(TIFF* tif)
|
|||||||
inflateEnd(&sp->stream);
|
inflateEnd(&sp->stream);
|
||||||
sp->state = 0;
|
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);
|
_TIFFfree(sp);
|
||||||
tif->tif_data = NULL;
|
tif->tif_data = NULL;
|
||||||
|
|
||||||
@ -344,15 +532,55 @@ ZIPVSetField(TIFF* tif, uint32 tag, va_list ap)
|
|||||||
switch (tag) {
|
switch (tag) {
|
||||||
case TIFFTAG_ZIPQUALITY:
|
case TIFFTAG_ZIPQUALITY:
|
||||||
sp->zipquality = (int) va_arg(ap, int);
|
sp->zipquality = (int) va_arg(ap, int);
|
||||||
|
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 ) {
|
if ( sp->state&ZSTATE_INIT_ENCODE ) {
|
||||||
|
int cappedQuality = sp->zipquality;
|
||||||
|
if( cappedQuality > Z_BEST_COMPRESSION )
|
||||||
|
cappedQuality = Z_BEST_COMPRESSION;
|
||||||
if (deflateParams(&sp->stream,
|
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",
|
TIFFErrorExt(tif->tif_clientdata, module, "ZLib error: %s",
|
||||||
SAFE_MSG(sp));
|
SAFE_MSG(sp));
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if LIBDEFLATE_SUPPORT
|
||||||
|
if( sp->libdeflate_enc )
|
||||||
|
{
|
||||||
|
libdeflate_free_compressor(sp->libdeflate_enc);
|
||||||
|
sp->libdeflate_enc = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return (1);
|
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:
|
default:
|
||||||
return (*sp->vsetparent)(tif, tag, ap);
|
return (*sp->vsetparent)(tif, tag, ap);
|
||||||
}
|
}
|
||||||
@ -368,6 +596,11 @@ ZIPVGetField(TIFF* tif, uint32 tag, va_list ap)
|
|||||||
case TIFFTAG_ZIPQUALITY:
|
case TIFFTAG_ZIPQUALITY:
|
||||||
*va_arg(ap, int*) = sp->zipquality;
|
*va_arg(ap, int*) = sp->zipquality;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TIFFTAG_DEFLATE_SUBCODEC:
|
||||||
|
*va_arg(ap, int*) = sp->subcodec;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return (*sp->vgetparent)(tif, tag, ap);
|
return (*sp->vgetparent)(tif, tag, ap);
|
||||||
}
|
}
|
||||||
@ -376,6 +609,7 @@ ZIPVGetField(TIFF* tif, uint32 tag, va_list ap)
|
|||||||
|
|
||||||
static const TIFFField zipFields[] = {
|
static const TIFFField zipFields[] = {
|
||||||
{ TIFFTAG_ZIPQUALITY, 0, 0, TIFF_ANY, 0, TIFF_SETGET_INT, TIFF_SETGET_UNDEFINED, FIELD_PSEUDO, TRUE, FALSE, "", NULL },
|
{ 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
|
int
|
||||||
@ -402,7 +636,7 @@ TIFFInitZIP(TIFF* tif, int scheme)
|
|||||||
/*
|
/*
|
||||||
* Allocate state block so tag methods have storage to record values.
|
* 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)
|
if (tif->tif_data == NULL)
|
||||||
goto bad;
|
goto bad;
|
||||||
sp = ZState(tif);
|
sp = ZState(tif);
|
||||||
@ -422,6 +656,11 @@ TIFFInitZIP(TIFF* tif, int scheme)
|
|||||||
/* Default values for codec-specific fields */
|
/* Default values for codec-specific fields */
|
||||||
sp->zipquality = Z_DEFAULT_COMPRESSION; /* default comp. level */
|
sp->zipquality = Z_DEFAULT_COMPRESSION; /* default comp. level */
|
||||||
sp->state = 0;
|
sp->state = 0;
|
||||||
|
#if LIBDEFLATE_SUPPORT
|
||||||
|
sp->subcodec = DEFLATE_SUBCODEC_LIBDEFLATE;
|
||||||
|
#else
|
||||||
|
sp->subcodec = DEFLATE_SUBCODEC_ZLIB;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Install codec methods.
|
* Install codec methods.
|
||||||
|
@ -658,6 +658,9 @@ typedef enum {
|
|||||||
#define TIFFTAG_LERC_MAXZERROR 65567 /* LERC maximum error */
|
#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_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_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
|
* EXIF tags
|
||||||
|
@ -87,6 +87,9 @@
|
|||||||
/* Support Deflate compression */
|
/* Support Deflate compression */
|
||||||
#cmakedefine ZIP_SUPPORT 1
|
#cmakedefine ZIP_SUPPORT 1
|
||||||
|
|
||||||
|
/* Support libdeflate enhanced compression */
|
||||||
|
#cmakedefine LIBDEFLATE_SUPPORT 1
|
||||||
|
|
||||||
/* Support strip chopping (whether or not to convert single-strip uncompressed
|
/* Support strip chopping (whether or not to convert single-strip uncompressed
|
||||||
images to mutiple strips of ~8Kb to reduce memory usage) */
|
images to mutiple strips of ~8Kb to reduce memory usage) */
|
||||||
#cmakedefine STRIPCHOP_DEFAULT 1
|
#cmakedefine STRIPCHOP_DEFAULT 1
|
||||||
|
@ -84,6 +84,9 @@
|
|||||||
/* Support Deflate compression */
|
/* Support Deflate compression */
|
||||||
#undef ZIP_SUPPORT
|
#undef ZIP_SUPPORT
|
||||||
|
|
||||||
|
/* Support libdeflate enhanced compression */
|
||||||
|
#undef LIBDEFLATE_SUPPORT
|
||||||
|
|
||||||
/* Support strip chopping (whether or not to convert single-strip uncompressed
|
/* Support strip chopping (whether or not to convert single-strip uncompressed
|
||||||
images to mutiple strips of ~8Kb to reduce memory usage) */
|
images to mutiple strips of ~8Kb to reduce memory usage) */
|
||||||
#undef STRIPCHOP_DEFAULT
|
#undef STRIPCHOP_DEFAULT
|
||||||
|
11
man/tiffcp.1
11
man/tiffcp.1
@ -151,6 +151,17 @@ e.g.
|
|||||||
for
|
for
|
||||||
.SM Deflate
|
.SM Deflate
|
||||||
encoding with maximum compression level and floating point predictor.
|
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
|
.TP
|
||||||
.B \-f
|
.B \-f
|
||||||
Specify the bit fill order to use in writing output data.
|
Specify the bit fill order to use in writing output data.
|
||||||
|
@ -97,6 +97,7 @@ static int jpegcolormode = JPEGCOLORMODE_RGB;
|
|||||||
static uint16 defcompression = (uint16) -1;
|
static uint16 defcompression = (uint16) -1;
|
||||||
static uint16 defpredictor = (uint16) -1;
|
static uint16 defpredictor = (uint16) -1;
|
||||||
static int defpreset = -1;
|
static int defpreset = -1;
|
||||||
|
static int subcodec = -1;
|
||||||
|
|
||||||
static int tiffcp(TIFF*, TIFF*);
|
static int tiffcp(TIFF*, TIFF*);
|
||||||
static int processCompressOptions(char*);
|
static int processCompressOptions(char*);
|
||||||
@ -361,6 +362,8 @@ processZIPOptions(char* cp)
|
|||||||
defpredictor = atoi(cp);
|
defpredictor = atoi(cp);
|
||||||
else if (*cp == 'p')
|
else if (*cp == 'p')
|
||||||
defpreset = atoi(++cp);
|
defpreset = atoi(++cp);
|
||||||
|
else if (*cp == 's')
|
||||||
|
subcodec = atoi(++cp);
|
||||||
else
|
else
|
||||||
usage(EXIT_FAILURE);
|
usage(EXIT_FAILURE);
|
||||||
} while( (cp = strchr(cp, ':')) );
|
} while( (cp = strchr(cp, ':')) );
|
||||||
@ -494,6 +497,9 @@ static const char* stuff[] = {
|
|||||||
"LZW, Deflate (ZIP), LZMA2, ZSTD and WEBP options:",
|
"LZW, Deflate (ZIP), LZMA2, ZSTD and WEBP options:",
|
||||||
" # set predictor value",
|
" # set predictor value",
|
||||||
" p# set compression level (preset)",
|
" 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,",
|
"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",
|
"-c zip:3:p9 for Deflate encoding with maximum compression level and floating",
|
||||||
"point predictor.",
|
"point predictor.",
|
||||||
@ -780,6 +786,17 @@ tiffcp(TIFF* in, TIFF* out)
|
|||||||
TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
|
TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
|
||||||
else
|
else
|
||||||
CopyField(TIFFTAG_PREDICTOR, predictor);
|
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*/
|
/*fallthrough*/
|
||||||
case COMPRESSION_WEBP:
|
case COMPRESSION_WEBP:
|
||||||
if (preset != -1) {
|
if (preset != -1) {
|
||||||
|
Loading…
Reference in New Issue
Block a user