add webp and zstd support to tiffsave
needs some tests still
This commit is contained in:
parent
063234fde1
commit
52ee3b083f
@ -5,6 +5,7 @@
|
||||
- add "unlimited" flag to svgload
|
||||
- disable webp alpha output if all frames fill the canvas and are solid
|
||||
- add "compression" option to heifsave [lovell]
|
||||
- support webp and zstd compression in tiff
|
||||
|
||||
24/5/19 started 8.8.1
|
||||
- improve realpath() use on older libc
|
||||
|
14
configure.ac
14
configure.ac
@ -1250,6 +1250,20 @@ if test x"$with_tiff" != x"no"; then
|
||||
)
|
||||
fi
|
||||
|
||||
# WEBP in TIFF added in libtiff 4.0.10
|
||||
if test x"$with_tiff" != x"no"; then
|
||||
save_INCLUDES="$INCLUDES"
|
||||
INCLUDES="$INCLUDES $TIFF_INCLUDES"
|
||||
AC_CHECK_DECL(COMPRESSION_WEBP,[
|
||||
AC_DEFINE(HAVE_TIFF_COMPRESSION_WEBP,1,[define if your libtiff has webp.])
|
||||
],[
|
||||
],[
|
||||
[#include <tiffio.h>]
|
||||
]
|
||||
)
|
||||
INCLUDES="$save_INCLUDES"
|
||||
fi
|
||||
|
||||
# giflib
|
||||
FIND_GIFLIB(
|
||||
[with_giflib="yes (found by search)"
|
||||
|
@ -28,8 +28,8 @@
|
||||
|
||||
*/
|
||||
|
||||
#ifndef VIPS_PARITHMETIC_H
|
||||
#define VIPS_PARITHMETIC_H
|
||||
#ifndef VIPS_PFOREIGN_H
|
||||
#define VIPS_PFOREIGN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -60,7 +60,8 @@ int vips__tiff_write( VipsImage *in, const char *filename,
|
||||
gboolean rgbjpeg,
|
||||
gboolean properties,
|
||||
gboolean strip,
|
||||
VipsRegionShrink region_shrink );
|
||||
VipsRegionShrink region_shrink,
|
||||
int level, gboolean lossless );
|
||||
|
||||
int vips__tiff_write_buf( VipsImage *in,
|
||||
void **obuf, size_t *olen,
|
||||
@ -75,7 +76,8 @@ int vips__tiff_write_buf( VipsImage *in,
|
||||
gboolean bigtiff,
|
||||
gboolean rgbjpeg,
|
||||
gboolean properties, gboolean strip,
|
||||
VipsRegionShrink region_shrink );
|
||||
VipsRegionShrink region_shrink,
|
||||
int level, gboolean lossless );
|
||||
|
||||
int vips__tiff_read_header( const char *filename, VipsImage *out,
|
||||
int page, int n, gboolean autorotate );
|
||||
@ -281,6 +283,6 @@ void vips__heif_error( struct heif_error *error );
|
||||
}
|
||||
#endif /*__cplusplus*/
|
||||
|
||||
#endif /*VIPS_PARITHMETIC_H*/
|
||||
#endif /*VIPS_PFOREIGN_H*/
|
||||
|
||||
|
||||
|
@ -14,6 +14,9 @@
|
||||
* - predictor defaults to horizontal, reducing file size, usually
|
||||
* 13/6/18
|
||||
* - add region_shrink
|
||||
* 8/7/19
|
||||
* - add webp and zstd support
|
||||
* - add @level and @lossless
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -88,6 +91,8 @@ typedef struct _VipsForeignSaveTiff {
|
||||
gboolean rgbjpeg;
|
||||
gboolean properties;
|
||||
VipsRegionShrink region_shrink;
|
||||
int level;
|
||||
gboolean lossless;
|
||||
} VipsForeignSaveTiff;
|
||||
|
||||
typedef VipsForeignSaveClass VipsForeignSaveTiffClass;
|
||||
@ -303,6 +308,20 @@ vips_foreign_save_tiff_class_init( VipsForeignSaveTiffClass *class )
|
||||
G_STRUCT_OFFSET( VipsForeignSaveTiff, region_shrink ),
|
||||
VIPS_TYPE_REGION_SHRINK, VIPS_REGION_SHRINK_MEAN );
|
||||
|
||||
VIPS_ARG_INT( class, "level", 23,
|
||||
_( "Level" ),
|
||||
_( "ZSTD compression level" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsForeignSaveTiff, level ),
|
||||
1, 22, 10 );
|
||||
|
||||
VIPS_ARG_BOOL( class, "lossless", 24,
|
||||
_( "lossless" ),
|
||||
_( "Enable WEBP lossless mode" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsForeignSaveTiff, lossless ),
|
||||
FALSE );
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
@ -317,6 +336,8 @@ vips_foreign_save_tiff_init( VipsForeignSaveTiff *tiff )
|
||||
tiff->xres = 1.0;
|
||||
tiff->yres = 1.0;
|
||||
tiff->region_shrink = VIPS_REGION_SHRINK_MEAN;
|
||||
tiff->level = 10;
|
||||
tiff->lossless = FALSE;
|
||||
}
|
||||
|
||||
typedef struct _VipsForeignSaveTiffFile {
|
||||
@ -353,7 +374,9 @@ vips_foreign_save_tiff_file_build( VipsObject *object )
|
||||
tiff->rgbjpeg,
|
||||
tiff->properties,
|
||||
save->strip,
|
||||
tiff->region_shrink ) )
|
||||
tiff->region_shrink,
|
||||
tiff->level,
|
||||
tiff->lossless ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
@ -422,7 +445,9 @@ vips_foreign_save_tiff_buffer_build( VipsObject *object )
|
||||
tiff->rgbjpeg,
|
||||
tiff->properties,
|
||||
save->strip,
|
||||
tiff->region_shrink ) )
|
||||
tiff->region_shrink,
|
||||
tiff->level,
|
||||
tiff->lossless ) )
|
||||
return( -1 );
|
||||
|
||||
/* vips__tiff_write_buf() makes a buffer that needs g_free(), not
|
||||
@ -488,7 +513,9 @@ vips_foreign_save_tiff_buffer_init( VipsForeignSaveTiffBuffer *buffer )
|
||||
* * @properties: set %TRUE to write an IMAGEDESCRIPTION tag
|
||||
* * @strip: set %TRUE to block metadata save
|
||||
* * @page_height: %gint for page height for multi-page save
|
||||
* * @shrink_region: #VipsRegionShrink How to shrink each 2x2 region.
|
||||
* * @region_shrink: #VipsRegionShrink How to shrink each 2x2 region.
|
||||
* * @level: %gint, Zstd compression level
|
||||
* * @lossless: set %TRUE for WebP losssless mode
|
||||
*
|
||||
* Write a VIPS image to a file as TIFF.
|
||||
*
|
||||
@ -497,13 +524,17 @@ vips_foreign_save_tiff_buffer_init( VipsForeignSaveTiffBuffer *buffer )
|
||||
* written as series of pages, each #VIPS_META_PAGE_HEIGHT pixels high.
|
||||
*
|
||||
* Use @compression to set the tiff compression. Currently jpeg, packbits,
|
||||
* fax4, lzw, none and deflate are supported. The default is no compression.
|
||||
* fax4, lzw, none, deflate, webp and zstd are supported. The default is no
|
||||
* compression.
|
||||
* JPEG compression is a good lossy compressor for photographs, packbits is
|
||||
* good for 1-bit images, and deflate is the best lossless compression TIFF
|
||||
* can do.
|
||||
*
|
||||
* Use @Q to set the JPEG compression factor. Default 75.
|
||||
*
|
||||
* User @level to set the ZSTD compression level. Use @lossless to
|
||||
* set WEBP lossless mode on. Use @Q to set the WEBP compression level.
|
||||
*
|
||||
* Use @predictor to set the predictor for lzw and deflate compression. It
|
||||
* defaults to #VIPS_FOREIGN_TIFF_PREDICTOR_HORIZONTAL, meaning horizontal
|
||||
* differencing. Please refer to the libtiff
|
||||
@ -522,7 +553,7 @@ vips_foreign_save_tiff_buffer_init( VipsForeignSaveTiffBuffer *buffer )
|
||||
* is 128 by 128.
|
||||
*
|
||||
* Set @pyramid to write the image as a set of images, one per page, of
|
||||
* decreasing size. Use @shrink_region to set how images will be shrunk: by
|
||||
* decreasing size. Use @region_shrink to set how images will be shrunk: by
|
||||
* default each 2x2 block is just averaged, but you can set MODE or MEDIAN as
|
||||
* well.
|
||||
*
|
||||
@ -601,7 +632,9 @@ vips_tiffsave( VipsImage *in, const char *filename, ... )
|
||||
* * @properties: set %TRUE to write an IMAGEDESCRIPTION tag
|
||||
* * @strip: set %TRUE to block metadata save
|
||||
* * @page_height: %gint for page height for multi-page save
|
||||
* * @shrink_region: #VipsRegionShrink How to shrink each 2x2 region.
|
||||
* * @region_shrink: #VipsRegionShrink How to shrink each 2x2 region.
|
||||
* * @level: %gint, Zstd compression level
|
||||
* * @lossless: set %TRUE for WebP losssless mode
|
||||
*
|
||||
* As vips_tiffsave(), but save to a memory buffer.
|
||||
*
|
||||
|
@ -182,6 +182,9 @@
|
||||
* - copy EXTRASAMPLES to pyramid layers
|
||||
* 21/12/18
|
||||
* - stop pyr layers if width or height drop to 1
|
||||
* 8/7/19
|
||||
* - add webp and zstd support
|
||||
* - add @level and @lossless
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -300,7 +303,7 @@ struct _Wtiff {
|
||||
int tls; /* Tile line size */
|
||||
|
||||
int compression; /* Compression type */
|
||||
int jpqual; /* JPEG q-factor */
|
||||
int Q; /* JPEG q-factor, webp level */
|
||||
int predictor; /* Predictor value */
|
||||
int tile; /* Tile or not */
|
||||
int tilew, tileh; /* Tile size */
|
||||
@ -316,6 +319,8 @@ struct _Wtiff {
|
||||
int properties; /* Set to save XML props */
|
||||
int strip; /* Don't write metadata */
|
||||
VipsRegionShrink region_shrink; /* How to shrink regions */
|
||||
int level; /* zstd compression level */
|
||||
gboolean lossless; /* webp lossless mode */
|
||||
|
||||
/* True if we've detected a toilet-roll image, plus the page height,
|
||||
* which has been checked to be a factor of im->Ysize.
|
||||
@ -583,7 +588,16 @@ wtiff_write_header( Wtiff *wtiff, Layer *layer )
|
||||
TIFFSetField( tif, TIFFTAG_COMPRESSION, wtiff->compression );
|
||||
|
||||
if( wtiff->compression == COMPRESSION_JPEG )
|
||||
TIFFSetField( tif, TIFFTAG_JPEGQUALITY, wtiff->jpqual );
|
||||
TIFFSetField( tif, TIFFTAG_JPEGQUALITY, wtiff->Q );
|
||||
|
||||
#ifdef HAVE_TIFF_COMPRESSION_WEBP
|
||||
if( wtiff->compression == COMPRESSION_WEBP ) {
|
||||
TIFFSetField( tif, TIFFTAG_WEBP_LEVEL, wtiff->Q );
|
||||
TIFFSetField( tif, TIFFTAG_WEBP_LOSSLESS, wtiff->lossless );
|
||||
}
|
||||
if( wtiff->compression == COMPRESSION_ZSTD )
|
||||
TIFFSetField( tif, TIFFTAG_ZSTD_LEVEL, wtiff->level );
|
||||
#endif /*HAVE_TIFF_COMPRESSION_WEBP*/
|
||||
|
||||
if( (wtiff->compression == VIPS_FOREIGN_TIFF_COMPRESSION_DEFLATE ||
|
||||
wtiff->compression == VIPS_FOREIGN_TIFF_COMPRESSION_LZW) &&
|
||||
@ -666,7 +680,7 @@ wtiff_write_header( Wtiff *wtiff, Layer *layer )
|
||||
else if( wtiff->compression == COMPRESSION_JPEG &&
|
||||
wtiff->im->Bands == 3 &&
|
||||
wtiff->im->BandFmt == VIPS_FORMAT_UCHAR &&
|
||||
(!wtiff->rgbjpeg && wtiff->jpqual < 90) ) {
|
||||
(!wtiff->rgbjpeg && wtiff->Q < 90) ) {
|
||||
/* This signals to libjpeg that it can do
|
||||
* YCbCr chrominance subsampling from RGB, not
|
||||
* that we will supply the image as YCbCr.
|
||||
@ -876,14 +890,16 @@ get_compression( VipsForeignTiffCompression compression )
|
||||
return( COMPRESSION_CCITTFAX4 );
|
||||
case VIPS_FOREIGN_TIFF_COMPRESSION_LZW:
|
||||
return( COMPRESSION_LZW );
|
||||
#ifdef HAVE_TIFF_COMPRESSION_WEBP
|
||||
case VIPS_FOREIGN_TIFF_COMPRESSION_WEBP:
|
||||
return( COMPRESSION_WEBP );
|
||||
case VIPS_FOREIGN_TIFF_COMPRESSION_ZSTD:
|
||||
return( COMPRESSION_ZSTD );
|
||||
#endif /*HAVE_TIFF_COMPRESSION_WEBP*/
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
return( COMPRESSION_NONE );
|
||||
}
|
||||
|
||||
/* Keep -Wall happy.
|
||||
*/
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
static int
|
||||
@ -918,7 +934,8 @@ wtiff_new( VipsImage *im, const char *filename,
|
||||
gboolean rgbjpeg,
|
||||
gboolean properties,
|
||||
gboolean strip,
|
||||
VipsRegionShrink region_shrink )
|
||||
VipsRegionShrink region_shrink,
|
||||
int level, gboolean lossless )
|
||||
{
|
||||
Wtiff *wtiff;
|
||||
|
||||
@ -930,7 +947,7 @@ wtiff_new( VipsImage *im, const char *filename,
|
||||
wtiff->layer = NULL;
|
||||
wtiff->tbuf = NULL;
|
||||
wtiff->compression = get_compression( compression );
|
||||
wtiff->jpqual = Q;
|
||||
wtiff->Q = Q;
|
||||
wtiff->predictor = predictor;
|
||||
wtiff->tile = tile;
|
||||
wtiff->tilew = tile_width;
|
||||
@ -947,6 +964,8 @@ wtiff_new( VipsImage *im, const char *filename,
|
||||
wtiff->properties = properties;
|
||||
wtiff->strip = strip;
|
||||
wtiff->region_shrink = region_shrink;
|
||||
wtiff->level = level;
|
||||
wtiff->lossless = lossless;
|
||||
wtiff->toilet_roll = FALSE;
|
||||
wtiff->page_height = vips_image_get_page_height( im );
|
||||
wtiff->image_height = im->Ysize;
|
||||
@ -1030,6 +1049,21 @@ wtiff_new( VipsImage *im, const char *filename,
|
||||
wtiff->miniswhite = FALSE;
|
||||
}
|
||||
|
||||
/* lossless is for webp only.
|
||||
*/
|
||||
#ifdef HAVE_TIFF_COMPRESSION_WEBP
|
||||
if( wtiff->lossless ) {
|
||||
if( wtiff->compression == COMPRESSION_NONE )
|
||||
wtiff->compression = COMPRESSION_WEBP;
|
||||
|
||||
if( wtiff->compression != COMPRESSION_WEBP ) {
|
||||
g_warning( "%s",
|
||||
_( "lossless is for WEBP compression only" ) );
|
||||
wtiff->lossless = FALSE;
|
||||
}
|
||||
}
|
||||
#endif /*HAVE_TIFF_COMPRESSION_WEBP*/
|
||||
|
||||
/* Sizeof a line of bytes in the TIFF tile.
|
||||
*/
|
||||
if( im->Coding == VIPS_CODING_LABQ )
|
||||
@ -1603,7 +1637,7 @@ wtiff_copy_tiff( Wtiff *wtiff, TIFF *out, TIFF *in )
|
||||
* Set explicitly from Wtiff.
|
||||
*/
|
||||
if( wtiff->compression == COMPRESSION_JPEG ) {
|
||||
TIFFSetField( out, TIFFTAG_JPEGQUALITY, wtiff->jpqual );
|
||||
TIFFSetField( out, TIFFTAG_JPEGQUALITY, wtiff->Q );
|
||||
|
||||
/* Only for three-band, 8-bit images.
|
||||
*/
|
||||
@ -1612,7 +1646,7 @@ wtiff_copy_tiff( Wtiff *wtiff, TIFF *out, TIFF *in )
|
||||
/* Enable rgb->ycbcr conversion in the jpeg write.
|
||||
*/
|
||||
if( !wtiff->rgbjpeg &&
|
||||
wtiff->jpqual < 90 )
|
||||
wtiff->Q < 90 )
|
||||
TIFFSetField( out,
|
||||
TIFFTAG_JPEGCOLORMODE,
|
||||
JPEGCOLORMODE_RGB );
|
||||
@ -1626,6 +1660,17 @@ wtiff_copy_tiff( Wtiff *wtiff, TIFF *out, TIFF *in )
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_TIFF_COMPRESSION_WEBP
|
||||
/* More pseudotags we can't copy.
|
||||
*/
|
||||
if( wtiff->compression == COMPRESSION_WEBP ) {
|
||||
TIFFSetField( out, TIFFTAG_WEBP_LEVEL, wtiff->Q );
|
||||
TIFFSetField( out, TIFFTAG_WEBP_LOSSLESS, wtiff->lossless );
|
||||
}
|
||||
if( wtiff->compression == COMPRESSION_ZSTD )
|
||||
TIFFSetField( out, TIFFTAG_ZSTD_LEVEL, wtiff->level );
|
||||
#endif /*HAVE_TIFF_COMPRESSION_WEBP*/
|
||||
|
||||
/* We can't copy profiles or xmp :( Set again from Wtiff.
|
||||
*/
|
||||
if( !wtiff->strip )
|
||||
@ -1785,7 +1830,8 @@ vips__tiff_write( VipsImage *in, const char *filename,
|
||||
gboolean bigtiff,
|
||||
gboolean rgbjpeg,
|
||||
gboolean properties, gboolean strip,
|
||||
VipsRegionShrink region_shrink )
|
||||
VipsRegionShrink region_shrink,
|
||||
int level, gboolean lossless )
|
||||
{
|
||||
Wtiff *wtiff;
|
||||
|
||||
@ -1802,7 +1848,7 @@ vips__tiff_write( VipsImage *in, const char *filename,
|
||||
compression, Q, predictor, profile,
|
||||
tile, tile_width, tile_height, pyramid, squash,
|
||||
miniswhite, resunit, xres, yres, bigtiff, rgbjpeg,
|
||||
properties, strip, region_shrink )) )
|
||||
properties, strip, region_shrink, level, lossless )) )
|
||||
return( -1 );
|
||||
|
||||
if( wtiff_write_image( wtiff ) ) {
|
||||
@ -1829,7 +1875,8 @@ vips__tiff_write_buf( VipsImage *in,
|
||||
gboolean bigtiff,
|
||||
gboolean rgbjpeg,
|
||||
gboolean properties, gboolean strip,
|
||||
VipsRegionShrink region_shrink )
|
||||
VipsRegionShrink region_shrink,
|
||||
int level, gboolean lossless )
|
||||
{
|
||||
Wtiff *wtiff;
|
||||
|
||||
@ -1842,7 +1889,7 @@ vips__tiff_write_buf( VipsImage *in,
|
||||
compression, Q, predictor, profile,
|
||||
tile, tile_width, tile_height, pyramid, squash,
|
||||
miniswhite, resunit, xres, yres, bigtiff, rgbjpeg,
|
||||
properties, strip, region_shrink )) )
|
||||
properties, strip, region_shrink, level, lossless )) )
|
||||
return( -1 );
|
||||
|
||||
wtiff->obuf = obuf;
|
||||
|
@ -406,12 +406,18 @@ int vips_webpsave_mime( VipsImage *in, ... )
|
||||
* @VIPS_FOREIGN_TIFF_COMPRESSION_PACKBITS: packbits compression
|
||||
* @VIPS_FOREIGN_TIFF_COMPRESSION_CCITTFAX4: fax4 compression
|
||||
* @VIPS_FOREIGN_TIFF_COMPRESSION_LZW: LZW compression
|
||||
* @VIPS_FOREIGN_TIFF_COMPRESSION_WEBP: WEBP compression
|
||||
* @VIPS_FOREIGN_TIFF_COMPRESSION_ZSTD: ZSTD compression
|
||||
*
|
||||
* The compression types supported by the tiff writer.
|
||||
*
|
||||
* Use @Q to set the jpeg compression level, default 75.
|
||||
*
|
||||
* Use @prediction to set the lzw or deflate prediction, default none.
|
||||
*
|
||||
* Use @lossless to set WEBP lossless compression.
|
||||
*
|
||||
* Use @level to set webp and zstd compression level.
|
||||
*/
|
||||
typedef enum {
|
||||
VIPS_FOREIGN_TIFF_COMPRESSION_NONE,
|
||||
@ -420,6 +426,8 @@ typedef enum {
|
||||
VIPS_FOREIGN_TIFF_COMPRESSION_PACKBITS,
|
||||
VIPS_FOREIGN_TIFF_COMPRESSION_CCITTFAX4,
|
||||
VIPS_FOREIGN_TIFF_COMPRESSION_LZW,
|
||||
VIPS_FOREIGN_TIFF_COMPRESSION_WEBP,
|
||||
VIPS_FOREIGN_TIFF_COMPRESSION_ZSTD,
|
||||
VIPS_FOREIGN_TIFF_COMPRESSION_LAST
|
||||
} VipsForeignTiffCompression;
|
||||
|
||||
|
@ -533,6 +533,8 @@ vips_foreign_tiff_compression_get_type( void )
|
||||
{VIPS_FOREIGN_TIFF_COMPRESSION_PACKBITS, "VIPS_FOREIGN_TIFF_COMPRESSION_PACKBITS", "packbits"},
|
||||
{VIPS_FOREIGN_TIFF_COMPRESSION_CCITTFAX4, "VIPS_FOREIGN_TIFF_COMPRESSION_CCITTFAX4", "ccittfax4"},
|
||||
{VIPS_FOREIGN_TIFF_COMPRESSION_LZW, "VIPS_FOREIGN_TIFF_COMPRESSION_LZW", "lzw"},
|
||||
{VIPS_FOREIGN_TIFF_COMPRESSION_WEBP, "VIPS_FOREIGN_TIFF_COMPRESSION_WEBP", "webp"},
|
||||
{VIPS_FOREIGN_TIFF_COMPRESSION_ZSTD, "VIPS_FOREIGN_TIFF_COMPRESSION_ZSTD", "zstd"},
|
||||
{VIPS_FOREIGN_TIFF_COMPRESSION_LAST, "VIPS_FOREIGN_TIFF_COMPRESSION_LAST", "last"},
|
||||
{0, NULL, NULL}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user