- use a single enum and switch that replaces no_subsample, force_subsample

This commit is contained in:
elad laufer 2020-02-17 11:29:57 +02:00
parent c626c9de14
commit d2b794ec35
7 changed files with 75 additions and 32 deletions

View File

@ -79,7 +79,7 @@ typedef struct _VipsForeignSaveJpeg {
/* Force chroma subsampling, if Q >= 90 then subsampling is disabled, use this flag to force it
*/
gboolean force_subsample;
VipsForeignJpegSubsample subsample_mode;
/* Apply trellis quantisation to each 8x8 block.
*/
@ -198,12 +198,13 @@ vips_foreign_save_jpeg_class_init( VipsForeignSaveJpegClass *class )
G_STRUCT_OFFSET( VipsForeignSaveJpeg, quant_table ),
0, 8, 0 );
VIPS_ARG_BOOL( class, "force_subsample", 19,
_( "Force subsample" ),
_( "Force chroma subsample" ),
VIPS_ARG_ENUM( class, "subsample_mode", 19,
_( "Subsample mode" ),
_( "Select chroma subsample operation mode" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveJpeg, force_subsample ),
FALSE );
G_STRUCT_OFFSET( VipsForeignSaveJpeg, subsample_mode ),
VIPS_TYPE_FOREIGN_JPEG_SUBSAMPLE,
VIPS_FOREIGN_JPEG_SUBSAMPLE_AUTO );
}
static void
@ -240,7 +241,7 @@ vips_foreign_save_jpeg_target_build( VipsObject *object )
jpeg->Q, jpeg->profile, jpeg->optimize_coding,
jpeg->interlace, save->strip, jpeg->no_subsample,
jpeg->trellis_quant, jpeg->overshoot_deringing,
jpeg->optimize_scans, jpeg->quant_table, jpeg->force_subsample ) )
jpeg->optimize_scans, jpeg->quant_table, jpeg->subsample_mode ) )
return( -1 );
return( 0 );
@ -307,7 +308,7 @@ vips_foreign_save_jpeg_file_build( VipsObject *object )
jpeg->Q, jpeg->profile, jpeg->optimize_coding,
jpeg->interlace, save->strip, jpeg->no_subsample,
jpeg->trellis_quant, jpeg->overshoot_deringing,
jpeg->optimize_scans, jpeg->quant_table, jpeg->force_subsample ) ) {
jpeg->optimize_scans, jpeg->quant_table, jpeg->subsample_mode ) ) {
VIPS_UNREF( target );
return( -1 );
}
@ -377,7 +378,7 @@ vips_foreign_save_jpeg_buffer_build( VipsObject *object )
jpeg->Q, jpeg->profile, jpeg->optimize_coding,
jpeg->interlace, save->strip, jpeg->no_subsample,
jpeg->trellis_quant, jpeg->overshoot_deringing,
jpeg->optimize_scans, jpeg->quant_table, jpeg->force_subsample ) ) {
jpeg->optimize_scans, jpeg->quant_table, jpeg->subsample_mode ) ) {
VIPS_UNREF( target );
return( -1 );
}
@ -450,7 +451,7 @@ vips_foreign_save_jpeg_mime_build( VipsObject *object )
jpeg->Q, jpeg->profile, jpeg->optimize_coding,
jpeg->interlace, save->strip, jpeg->no_subsample,
jpeg->trellis_quant, jpeg->overshoot_deringing,
jpeg->optimize_scans, jpeg->quant_table, jpeg->force_subsample ) ) {
jpeg->optimize_scans, jpeg->quant_table, jpeg->subsample_mode ) ) {
VIPS_UNREF( target );
return( -1 );
}

View File

@ -166,7 +166,7 @@ int vips__jpeg_write_target( VipsImage *in, VipsTarget *target,
gboolean optimize_coding, gboolean progressive, gboolean strip,
gboolean no_subsample, gboolean trellis_quant,
gboolean overshoot_deringing, gboolean optimize_scans,
int quant_table, gboolean force_subsample );
int quant_table, VipsForeignJpegSubsample subsample_mode );
int vips__jpeg_read_source( VipsSource *source, VipsImage *out,
gboolean header_only, int shrink, int fail, gboolean autorotate );

View File

@ -481,7 +481,7 @@ write_vips( Write *write, int qfac, const char *profile,
gboolean optimize_coding, gboolean progressive, gboolean strip,
gboolean no_subsample, gboolean trellis_quant,
gboolean overshoot_deringing, gboolean optimize_scans, int quant_table,
gboolean force_subsample)
VipsForeignJpegSubsample subsample_mode)
{
VipsImage *in;
J_COLOR_SPACE space;
@ -628,18 +628,25 @@ write_vips( Write *write, int qfac, const char *profile,
if( progressive )
jpeg_simple_progression( &write->cinfo );
/* Turn off chroma subsampling. Follow IM and do it automatically for
* high Q.
*/
if( !force_subsample && (
no_subsample ||
qfac >= 90 )) {
int i;
for( i = 0; i < in->Bands; i++ ) {
write->cinfo.comp_info[i].h_samp_factor = 1;
write->cinfo.comp_info[i].v_samp_factor = 1;
}
switch (subsample_mode) {
case VIPS_FOREIGN_JPEG_SUBSAMPLE_ON:
break;
case VIPS_FOREIGN_JPEG_SUBSAMPLE_AUTO:
/* Turn off chroma subsampling. Follow IM and do it automatically for
* high Q.
*/
if( !(no_subsample ||
qfac >= 90) ) {
break;
}
case VIPS_FOREIGN_JPEG_SUBSAMPLE_OFF:
default: {
int i;
for (i = 0; i < in->Bands; i++) {
write->cinfo.comp_info[i].h_samp_factor = 1;
write->cinfo.comp_info[i].v_samp_factor = 1;
}
}
}
/* Don't write the APP0 JFIF headers if we are stripping.
@ -778,7 +785,7 @@ vips__jpeg_write_target( VipsImage *in, VipsTarget *target,
gboolean optimize_coding, gboolean progressive,
gboolean strip, gboolean no_subsample, gboolean trellis_quant,
gboolean overshoot_deringing, gboolean optimize_scans, int quant_table,
gboolean force_subsample)
VipsForeignJpegSubsample subsample_mode)
{
Write *write;
@ -805,7 +812,7 @@ vips__jpeg_write_target( VipsImage *in, VipsTarget *target,
if( write_vips( write,
Q, profile, optimize_coding, progressive, strip, no_subsample,
trellis_quant, overshoot_deringing, optimize_scans,
quant_table, force_subsample ) ) {
quant_table, subsample_mode ) ) {
write_destroy( write );
return( -1 );
}

View File

@ -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_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;
#define VIPS_TYPE_FOREIGN_WEBP_PRESET (vips_foreign_webp_preset_get_type())
GType vips_foreign_tiff_compression_get_type (void) G_GNUC_CONST;

View File

@ -364,6 +364,18 @@ int vips_vipssave( VipsImage *in, const char *filename, ... )
int vips_openslideload( const char *filename, VipsImage **out, ... )
__attribute__((sentinel));
/**
* VipsForeignJpegSubsample:
* @VIPS_FOREIGN_JPEG_SUBSAMPLE_AUTO: default preset
* @VIPS_FOREIGN_JPEG_SUBSAMPLE_ON: always perform subsampling
* @VIPS_FOREIGN_JPEG_SUBSAMPLE_ON: never perform subsampling
*/
typedef enum {
VIPS_FOREIGN_JPEG_SUBSAMPLE_AUTO,
VIPS_FOREIGN_JPEG_SUBSAMPLE_ON,
VIPS_FOREIGN_JPEG_SUBSAMPLE_OFF
} VipsForeignJpegSubsample;
int vips_jpegload( const char *filename, VipsImage **out, ... )
__attribute__((sentinel));
int vips_jpegload_buffer( void *buf, size_t len, VipsImage **out, ... )

View File

@ -499,6 +499,24 @@ vips_saveable_get_type( void )
return( etype );
}
GType
vips_foreign_jpeg_subsample_get_type( void )
{
static GType etype = 0;
if( etype == 0 ) {
static const GEnumValue values[] = {
{VIPS_FOREIGN_JPEG_SUBSAMPLE_AUTO, "VIPS_FOREIGN_JPEG_SUBSAMPLE_AUTO", "auto"},
{VIPS_FOREIGN_JPEG_SUBSAMPLE_ON, "VIPS_FOREIGN_JPEG_SUBSAMPLE_ON", "on"},
{VIPS_FOREIGN_JPEG_SUBSAMPLE_OFF, "VIPS_FOREIGN_JPEG_SUBSAMPLE_OFF", "off"},
{0, NULL, NULL}
};
etype = g_enum_register_static( "VipsForeignJpegSubsample", values );
}
return( etype );
}
GType
vips_foreign_webp_preset_get_type( void )
{
static GType etype = 0;

View File

@ -259,14 +259,17 @@ class TestForeign:
im = pyvips.Image.new_from_file(JPEG_FILE)
# higher Q should mean a bigger buffer
b1 = im.jpegsave_buffer(Q=10)
b2 = im.jpegsave_buffer(Q=90)
assert len(b2) > len(b1)
q10 = im.jpegsave_buffer(Q=10)
q10o = im.jpegsave_buffer(Q=10, subsample_mode=2)
q90 = im.jpegsave_buffer(Q=90)
assert len(q90) > len(q10)
assert len(q10o) > len(q10)
# force subsampling should result in smaller buffer
b1 = im.jpegsave_buffer(Q=90, force_subsample=True)
b2 = im.jpegsave_buffer(Q=90)
assert len(b2) > len(b1)
q90s = im.jpegsave_buffer(Q=90, subsample_mode=1)
q90a = im.jpegsave_buffer(Q=90, subsample_mode=0)
assert len(q90) > len(q90s)
assert len(q90) == len(q90a)
@skip_if_no("jpegload")
def test_truncated(self):