heifsave: add option to control subsample_mode
Defaults to no subsampling when Q>90 for consistency with jpegsave. Deprecate VipsForeignJpegSubsample enum, replace with more generic VipsForeignSubsample.
This commit is contained in:
parent
3cd774a10c
commit
3ad7363104
@ -2977,6 +2977,8 @@ static VImage heifload_source( VSource source, VOption *options = 0 );
|
||||
* - **Q** -- Q factor, int.
|
||||
* - **lossless** -- Enable lossless compression, bool.
|
||||
* - **compression** -- Compression format, VipsForeignHeifCompression.
|
||||
* - **speed**: -- CPU effort, 0 slowest - 8 fastest, AV1 compression only, int.
|
||||
* - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample.
|
||||
* - **strip** -- Strip all metadata from image, bool.
|
||||
* - **background** -- Background value, std::vector<double>.
|
||||
* - **page_height** -- Set page height for multipage save, int.
|
||||
@ -2993,6 +2995,8 @@ void heifsave( const char *filename, VOption *options = 0 ) const;
|
||||
* - **Q** -- Q factor, int.
|
||||
* - **lossless** -- Enable lossless compression, bool.
|
||||
* - **compression** -- Compression format, VipsForeignHeifCompression.
|
||||
* - **speed**: -- CPU effort, 0 slowest - 8 fastest, AV1 compression only, int.
|
||||
* - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample.
|
||||
* - **strip** -- Strip all metadata from image, bool.
|
||||
* - **background** -- Background value, std::vector<double>.
|
||||
* - **page_height** -- Set page height for multipage save, int.
|
||||
@ -3009,6 +3013,8 @@ VipsBlob *heifsave_buffer( VOption *options = 0 ) const;
|
||||
* - **Q** -- Q factor, int.
|
||||
* - **lossless** -- Enable lossless compression, bool.
|
||||
* - **compression** -- Compression format, VipsForeignHeifCompression.
|
||||
* - **speed**: -- CPU effort, 0 slowest - 8 fastest, AV1 compression only, int.
|
||||
* - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample.
|
||||
* - **strip** -- Strip all metadata from image, bool.
|
||||
* - **background** -- Background value, std::vector<double>.
|
||||
* - **page_height** -- Set page height for multipage save, int.
|
||||
@ -3341,7 +3347,7 @@ static VImage jpegload_source( VSource source, VOption *options = 0 );
|
||||
* - **overshoot_deringing** -- Apply overshooting to samples with extreme values, bool.
|
||||
* - **optimize_scans** -- Split spectrum of DCT coefficients into separate scans, bool.
|
||||
* - **quant_table** -- Use predefined quantization table with given index, int.
|
||||
* - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignJpegSubsample.
|
||||
* - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample.
|
||||
* - **strip** -- Strip all metadata from image, bool.
|
||||
* - **background** -- Background value, std::vector<double>.
|
||||
* - **page_height** -- Set page height for multipage save, int.
|
||||
@ -3364,7 +3370,7 @@ void jpegsave( const char *filename, VOption *options = 0 ) const;
|
||||
* - **overshoot_deringing** -- Apply overshooting to samples with extreme values, bool.
|
||||
* - **optimize_scans** -- Split spectrum of DCT coefficients into separate scans, bool.
|
||||
* - **quant_table** -- Use predefined quantization table with given index, int.
|
||||
* - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignJpegSubsample.
|
||||
* - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample.
|
||||
* - **strip** -- Strip all metadata from image, bool.
|
||||
* - **background** -- Background value, std::vector<double>.
|
||||
* - **page_height** -- Set page height for multipage save, int.
|
||||
@ -3387,7 +3393,7 @@ VipsBlob *jpegsave_buffer( VOption *options = 0 ) const;
|
||||
* - **overshoot_deringing** -- Apply overshooting to samples with extreme values, bool.
|
||||
* - **optimize_scans** -- Split spectrum of DCT coefficients into separate scans, bool.
|
||||
* - **quant_table** -- Use predefined quantization table with given index, int.
|
||||
* - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignJpegSubsample.
|
||||
* - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample.
|
||||
* - **strip** -- Strip all metadata from image, bool.
|
||||
* - **background** -- Background value, std::vector<double>.
|
||||
* - **page_height** -- Set page height for multipage save, int.
|
||||
@ -3409,7 +3415,7 @@ void jpegsave_mime( VOption *options = 0 ) const;
|
||||
* - **overshoot_deringing** -- Apply overshooting to samples with extreme values, bool.
|
||||
* - **optimize_scans** -- Split spectrum of DCT coefficients into separate scans, bool.
|
||||
* - **quant_table** -- Use predefined quantization table with given index, int.
|
||||
* - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignJpegSubsample.
|
||||
* - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample.
|
||||
* - **strip** -- Strip all metadata from image, bool.
|
||||
* - **background** -- Background value, std::vector<double>.
|
||||
* - **page_height** -- Set page height for multipage save, int.
|
||||
|
@ -83,6 +83,10 @@ typedef struct _VipsForeignSaveHeif {
|
||||
*/
|
||||
int speed;
|
||||
|
||||
/* Chroma subsampling.
|
||||
*/
|
||||
VipsForeignSubsample subsample_mode;
|
||||
|
||||
/* The image we save. This is a copy of save->ready since we need to
|
||||
* be able to update the metadata.
|
||||
*/
|
||||
@ -319,6 +323,7 @@ vips_foreign_save_heif_build( VipsObject *object )
|
||||
|
||||
struct heif_error error;
|
||||
struct heif_writer writer;
|
||||
char *chroma;
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_foreign_save_heif_parent_class )->
|
||||
build( object ) )
|
||||
@ -363,6 +368,17 @@ vips_foreign_save_heif_build( VipsObject *object )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
chroma = heif->subsample_mode == VIPS_FOREIGN_SUBSAMPLE_OFF ||
|
||||
( heif->subsample_mode == VIPS_FOREIGN_SUBSAMPLE_AUTO &&
|
||||
heif->Q > 90 ) ? "444" : "420";
|
||||
error = heif_encoder_set_parameter_string( heif->encoder,
|
||||
"chroma", chroma );
|
||||
if( error.code &&
|
||||
error.subcode != heif_suberror_Unsupported_parameter ) {
|
||||
vips__heif_error( &error );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* TODO .. support extra per-encoder params with
|
||||
* heif_encoder_list_parameters().
|
||||
*/
|
||||
@ -487,6 +503,13 @@ vips_foreign_save_heif_class_init( VipsForeignSaveHeifClass *class )
|
||||
G_STRUCT_OFFSET( VipsForeignSaveHeif, speed ),
|
||||
0, 8, 5 );
|
||||
|
||||
VIPS_ARG_ENUM( class, "subsample_mode", 16,
|
||||
_( "Subsample mode" ),
|
||||
_( "Select chroma subsample operation mode" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsForeignSaveHeif, subsample_mode ),
|
||||
VIPS_TYPE_FOREIGN_SUBSAMPLE,
|
||||
VIPS_FOREIGN_SUBSAMPLE_AUTO );
|
||||
}
|
||||
|
||||
static void
|
||||
@ -496,6 +519,7 @@ vips_foreign_save_heif_init( VipsForeignSaveHeif *heif )
|
||||
heif->Q = 50;
|
||||
heif->compression = VIPS_FOREIGN_HEIF_COMPRESSION_HEVC;
|
||||
heif->speed = 5;
|
||||
heif->subsample_mode = VIPS_FOREIGN_SUBSAMPLE_AUTO;
|
||||
}
|
||||
|
||||
typedef struct _VipsForeignSaveHeifFile {
|
||||
@ -689,6 +713,7 @@ vips_foreign_save_heif_target_init( VipsForeignSaveHeifTarget *target )
|
||||
* * @lossless: %gboolean, enable lossless encoding
|
||||
* * @compression: #VipsForeignHeifCompression, write with this compression
|
||||
* * @speed: %gint, CPU effort, 0 slowest - 8 fastest, AV1 compression only
|
||||
* * @subsample_mode: #VipsForeignSubsample, chroma subsampling mode
|
||||
*
|
||||
* Write a VIPS image to a file in HEIF format.
|
||||
*
|
||||
@ -702,6 +727,9 @@ vips_foreign_save_heif_target_init( VipsForeignSaveHeifTarget *target )
|
||||
* Use @speed to control the CPU effort spent improving compression.
|
||||
* This is currently only applicable to AV1 encoders, defaults to 5.
|
||||
*
|
||||
* Chroma subsampling is normally automatically disabled for Q > 90. You can
|
||||
* force the subsampling mode with @subsample_mode.
|
||||
*
|
||||
* See also: vips_image_write_to_file(), vips_heifload().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error.
|
||||
@ -732,6 +760,7 @@ vips_heifsave( VipsImage *in, const char *filename, ... )
|
||||
* * @lossless: %gboolean, enable lossless encoding
|
||||
* * @compression: #VipsForeignHeifCompression, write with this compression
|
||||
* * @speed: %gint, CPU effort, 0 slowest - 8 fastest, AV1 compression only
|
||||
* * @subsample_mode: #VipsForeignSubsample, chroma subsampling mode
|
||||
*
|
||||
* As vips_heifsave(), but save to a memory buffer.
|
||||
*
|
||||
@ -783,6 +812,7 @@ vips_heifsave_buffer( VipsImage *in, void **buf, size_t *len, ... )
|
||||
* * @lossless: %gboolean, enable lossless encoding
|
||||
* * @compression: #VipsForeignHeifCompression, write with this compression
|
||||
* * @speed: %gint, CPU effort, 0 slowest - 8 fastest, AV1 compression only
|
||||
* * @subsample_mode: #VipsForeignSubsample, chroma subsampling mode
|
||||
*
|
||||
* As vips_heifsave(), but save to a target.
|
||||
*
|
||||
|
@ -84,7 +84,7 @@ typedef struct _VipsForeignSaveJpeg {
|
||||
* on will always enable subsampling
|
||||
* off will always disable subsampling
|
||||
*/
|
||||
VipsForeignJpegSubsample subsample_mode;
|
||||
VipsForeignSubsample subsample_mode;
|
||||
|
||||
/* Apply trellis quantisation to each 8x8 block.
|
||||
*/
|
||||
@ -133,8 +133,8 @@ vips_foreign_save_jpeg_build( VipsObject *object )
|
||||
*/
|
||||
if( vips_object_argument_isset( object, "no_subsample" ) )
|
||||
jpeg->subsample_mode = jpeg->no_subsample ?
|
||||
VIPS_FOREIGN_JPEG_SUBSAMPLE_OFF :
|
||||
VIPS_FOREIGN_JPEG_SUBSAMPLE_AUTO;
|
||||
VIPS_FOREIGN_SUBSAMPLE_OFF :
|
||||
VIPS_FOREIGN_SUBSAMPLE_AUTO;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
@ -229,15 +229,15 @@ vips_foreign_save_jpeg_class_init( VipsForeignSaveJpegClass *class )
|
||||
_( "Select chroma subsample operation mode" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsForeignSaveJpeg, subsample_mode ),
|
||||
VIPS_TYPE_FOREIGN_JPEG_SUBSAMPLE,
|
||||
VIPS_FOREIGN_JPEG_SUBSAMPLE_AUTO );
|
||||
VIPS_TYPE_FOREIGN_SUBSAMPLE,
|
||||
VIPS_FOREIGN_SUBSAMPLE_AUTO );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_save_jpeg_init( VipsForeignSaveJpeg *jpeg )
|
||||
{
|
||||
jpeg->Q = 75;
|
||||
jpeg->subsample_mode = VIPS_FOREIGN_JPEG_SUBSAMPLE_AUTO;
|
||||
jpeg->subsample_mode = VIPS_FOREIGN_SUBSAMPLE_AUTO;
|
||||
}
|
||||
|
||||
typedef struct _VipsForeignSaveJpegTarget {
|
||||
@ -529,7 +529,7 @@ vips_foreign_save_jpeg_mime_init( VipsForeignSaveJpegMime *mime )
|
||||
* * @optimize_coding: %gboolean, compute optimal Huffman coding tables
|
||||
* * @interlace: %gboolean, write an interlaced (progressive) jpeg
|
||||
* * @strip: %gboolean, remove all metadata from image
|
||||
* * @subsample_mode: #VipsForeignJpegSubsample, chroma subsampling mode
|
||||
* * @subsample_mode: #VipsForeignSubsample, chroma subsampling mode
|
||||
* * @trellis_quant: %gboolean, apply trellis quantisation to each 8x8 block
|
||||
* * @overshoot_deringing: %gboolean, overshoot samples with extreme values
|
||||
* * @optimize_scans: %gboolean, split DCT coefficients into separate scans
|
||||
@ -558,7 +558,7 @@ vips_foreign_save_jpeg_mime_init( VipsForeignSaveJpegMime *mime )
|
||||
* written into the output file.
|
||||
*
|
||||
* Chroma subsampling is normally automatically disabled for Q > 90. You can
|
||||
* force the subsampling mode with @@subsample_mode.
|
||||
* force the subsampling mode with @subsample_mode.
|
||||
*
|
||||
* If @trellis_quant is set and the version of libjpeg supports it
|
||||
* (e.g. mozjpeg >= 3.0), apply trellis quantisation to each 8x8 block.
|
||||
@ -645,7 +645,7 @@ vips_jpegsave( VipsImage *in, const char *filename, ... )
|
||||
* * @optimize_coding: %gboolean, compute optimal Huffman coding tables
|
||||
* * @interlace: %gboolean, write an interlaced (progressive) jpeg
|
||||
* * @strip: %gboolean, remove all metadata from image
|
||||
* * @subsample_mode: #VipsForeignJpegSubsample, chroma subsampling mode
|
||||
* * @subsample_mode: #VipsForeignSubsample, chroma subsampling mode
|
||||
* * @trellis_quant: %gboolean, apply trellis quantisation to each 8x8 block
|
||||
* * @overshoot_deringing: %gboolean, overshoot samples with extreme values
|
||||
* * @optimize_scans: %gboolean, split DCT coefficients into separate scans
|
||||
@ -684,7 +684,7 @@ vips_jpegsave_target( VipsImage *in, VipsTarget *target, ... )
|
||||
* * @optimize_coding: %gboolean, compute optimal Huffman coding tables
|
||||
* * @interlace: %gboolean, write an interlaced (progressive) jpeg
|
||||
* * @strip: %gboolean, remove all metadata from image
|
||||
* * @subsample_mode: #VipsForeignJpegSubsample, chroma subsampling mode
|
||||
* * @subsample_mode: #VipsForeignSubsample, chroma subsampling mode
|
||||
* * @trellis_quant: %gboolean, apply trellis quantisation to each 8x8 block
|
||||
* * @overshoot_deringing: %gboolean, overshoot samples with extreme values
|
||||
* * @optimize_scans: %gboolean, split DCT coefficients into separate scans
|
||||
@ -740,7 +740,7 @@ vips_jpegsave_buffer( VipsImage *in, void **buf, size_t *len, ... )
|
||||
* * @optimize_coding: %gboolean, compute optimal Huffman coding tables
|
||||
* * @interlace: %gboolean, write an interlaced (progressive) jpeg
|
||||
* * @strip: %gboolean, remove all metadata from image
|
||||
* * @subsample_mode: #VipsForeignJpegSubsample, chroma subsampling mode
|
||||
* * @subsample_mode: #VipsForeignSubsample, chroma subsampling mode
|
||||
* * @trellis_quant: %gboolean, apply trellis quantisation to each 8x8 block
|
||||
* * @overshoot_deringing: %gboolean, overshoot samples with extreme values
|
||||
* * @optimize_scans: %gboolean, split DCT coefficients into separate scans
|
||||
|
@ -168,7 +168,7 @@ int vips__jpeg_write_target( VipsImage *in, VipsTarget *target,
|
||||
gboolean optimize_coding, gboolean progressive, gboolean strip,
|
||||
gboolean trellis_quant, gboolean overshoot_deringing,
|
||||
gboolean optimize_scans, int quant_table,
|
||||
VipsForeignJpegSubsample subsample_mode );
|
||||
VipsForeignSubsample subsample_mode );
|
||||
|
||||
int vips__jpeg_read_source( VipsSource *source, VipsImage *out,
|
||||
gboolean header_only, int shrink, int fail, gboolean autorotate );
|
||||
|
@ -540,7 +540,7 @@ write_vips( Write *write, int qfac, const char *profile,
|
||||
gboolean optimize_coding, gboolean progressive, gboolean strip,
|
||||
gboolean trellis_quant, gboolean overshoot_deringing,
|
||||
gboolean optimize_scans, int quant_table,
|
||||
VipsForeignJpegSubsample subsample_mode )
|
||||
VipsForeignSubsample subsample_mode )
|
||||
{
|
||||
VipsImage *in;
|
||||
J_COLOR_SPACE space;
|
||||
@ -687,8 +687,8 @@ write_vips( Write *write, int qfac, const char *profile,
|
||||
if( progressive )
|
||||
jpeg_simple_progression( &write->cinfo );
|
||||
|
||||
if( subsample_mode == VIPS_FOREIGN_JPEG_SUBSAMPLE_OFF ||
|
||||
(subsample_mode == VIPS_FOREIGN_JPEG_SUBSAMPLE_AUTO &&
|
||||
if( subsample_mode == VIPS_FOREIGN_SUBSAMPLE_OFF ||
|
||||
(subsample_mode == VIPS_FOREIGN_SUBSAMPLE_AUTO &&
|
||||
qfac >= 90) ) {
|
||||
int i;
|
||||
|
||||
@ -846,7 +846,7 @@ vips__jpeg_write_target( VipsImage *in, VipsTarget *target,
|
||||
gboolean optimize_coding, gboolean progressive,
|
||||
gboolean strip, gboolean trellis_quant,
|
||||
gboolean overshoot_deringing, gboolean optimize_scans,
|
||||
int quant_table, VipsForeignJpegSubsample subsample_mode)
|
||||
int quant_table, VipsForeignSubsample subsample_mode)
|
||||
{
|
||||
Write *write;
|
||||
|
||||
|
@ -58,6 +58,8 @@ GType vips_foreign_flags_get_type (void) G_GNUC_CONST;
|
||||
#define VIPS_TYPE_FOREIGN_FLAGS (vips_foreign_flags_get_type())
|
||||
GType vips_saveable_get_type (void) G_GNUC_CONST;
|
||||
#define VIPS_TYPE_SAVEABLE (vips_saveable_get_type())
|
||||
GType vips_foreign_subsample_get_type (void) G_GNUC_CONST;
|
||||
#define VIPS_TYPE_FOREIGN_SUBSAMPLE (vips_foreign_subsample_get_type())
|
||||
GType vips_foreign_jpeg_subsample_get_type (void) G_GNUC_CONST;
|
||||
#define VIPS_TYPE_FOREIGN_JPEG_SUBSAMPLE (vips_foreign_jpeg_subsample_get_type())
|
||||
GType vips_foreign_webp_preset_get_type (void) G_GNUC_CONST;
|
||||
|
@ -370,6 +370,21 @@ int vips_openslideload( const char *filename, VipsImage **out, ... )
|
||||
int vips_openslideload_source( VipsSource *source, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
|
||||
/**
|
||||
* VipsForeignSubsample:
|
||||
* @VIPS_FOREIGN_SUBSAMPLE_AUTO: prevent subsampling when quality > 90
|
||||
* @VIPS_FOREIGN_SUBSAMPLE_ON: always perform subsampling
|
||||
* @VIPS_FOREIGN_SUBSAMPLE_OFF: never perform subsampling
|
||||
*
|
||||
* Set subsampling mode.
|
||||
*/
|
||||
typedef enum {
|
||||
VIPS_FOREIGN_SUBSAMPLE_AUTO,
|
||||
VIPS_FOREIGN_SUBSAMPLE_ON,
|
||||
VIPS_FOREIGN_SUBSAMPLE_OFF,
|
||||
VIPS_FOREIGN_SUBSAMPLE_LAST
|
||||
} VipsForeignSubsample;
|
||||
|
||||
/**
|
||||
* VipsForeignJpegSubsample:
|
||||
* @VIPS_FOREIGN_JPEG_SUBSAMPLE_AUTO: default preset
|
||||
@ -377,6 +392,8 @@ int vips_openslideload_source( VipsSource *source, VipsImage **out, ... )
|
||||
* @VIPS_FOREIGN_JPEG_SUBSAMPLE_OFF: never perform subsampling
|
||||
*
|
||||
* Set jpeg subsampling mode.
|
||||
*
|
||||
* DEPRECATED: use #VipsForeignSubsample
|
||||
*/
|
||||
typedef enum {
|
||||
VIPS_FOREIGN_JPEG_SUBSAMPLE_AUTO,
|
||||
|
@ -500,6 +500,25 @@ vips_saveable_get_type( void )
|
||||
return( etype );
|
||||
}
|
||||
GType
|
||||
vips_foreign_subsample_get_type( void )
|
||||
{
|
||||
static GType etype = 0;
|
||||
|
||||
if( etype == 0 ) {
|
||||
static const GEnumValue values[] = {
|
||||
{VIPS_FOREIGN_SUBSAMPLE_AUTO, "VIPS_FOREIGN_SUBSAMPLE_AUTO", "auto"},
|
||||
{VIPS_FOREIGN_SUBSAMPLE_ON, "VIPS_FOREIGN_SUBSAMPLE_ON", "on"},
|
||||
{VIPS_FOREIGN_SUBSAMPLE_OFF, "VIPS_FOREIGN_SUBSAMPLE_OFF", "off"},
|
||||
{VIPS_FOREIGN_SUBSAMPLE_LAST, "VIPS_FOREIGN_SUBSAMPLE_LAST", "last"},
|
||||
{0, NULL, NULL}
|
||||
};
|
||||
|
||||
etype = g_enum_register_static( "VipsForeignSubsample", values );
|
||||
}
|
||||
|
||||
return( etype );
|
||||
}
|
||||
GType
|
||||
vips_foreign_jpeg_subsample_get_type( void )
|
||||
{
|
||||
static GType etype = 0;
|
||||
|
@ -1104,6 +1104,11 @@ class TestForeign:
|
||||
b2 = self.mono.heifsave_buffer(Q=90, compression="av1")
|
||||
assert len(b2) > len(b1)
|
||||
|
||||
# Chroma subsampling should produce smaller file size for same Q
|
||||
b1 = self.colour.heifsave_buffer(compression="av1", subsample_mode="on")
|
||||
b2 = self.colour.heifsave_buffer(compression="av1", subsample_mode="off")
|
||||
assert len(b2) > len(b1)
|
||||
|
||||
# try saving an image with an ICC profile and reading it back
|
||||
# not all libheif have profile support, so put it in an if
|
||||
buf = self.colour.heifsave_buffer(Q=10, compression="av1")
|
||||
|
Loading…
Reference in New Issue
Block a user