Use a single enum and switch that replaces no_subsample, force_subsample
This commit is contained in:
commit
4c6df5b906
|
@ -79,7 +79,7 @@ typedef struct _VipsForeignSaveJpeg {
|
||||||
|
|
||||||
/* Force chroma subsampling, if Q >= 90 then subsampling is disabled, use this flag to force it
|
/* 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.
|
/* 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 ),
|
G_STRUCT_OFFSET( VipsForeignSaveJpeg, quant_table ),
|
||||||
0, 8, 0 );
|
0, 8, 0 );
|
||||||
|
|
||||||
VIPS_ARG_BOOL( class, "force_subsample", 19,
|
VIPS_ARG_ENUM( class, "subsample_mode", 19,
|
||||||
_( "Force subsample" ),
|
_( "Subsample mode" ),
|
||||||
_( "Force chroma subsample" ),
|
_( "Select chroma subsample operation mode" ),
|
||||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||||
G_STRUCT_OFFSET( VipsForeignSaveJpeg, force_subsample ),
|
G_STRUCT_OFFSET( VipsForeignSaveJpeg, subsample_mode ),
|
||||||
FALSE );
|
VIPS_TYPE_FOREIGN_JPEG_SUBSAMPLE,
|
||||||
|
VIPS_FOREIGN_JPEG_SUBSAMPLE_AUTO );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -240,7 +241,7 @@ vips_foreign_save_jpeg_target_build( VipsObject *object )
|
||||||
jpeg->Q, jpeg->profile, jpeg->optimize_coding,
|
jpeg->Q, jpeg->profile, jpeg->optimize_coding,
|
||||||
jpeg->interlace, save->strip, jpeg->no_subsample,
|
jpeg->interlace, save->strip, jpeg->no_subsample,
|
||||||
jpeg->trellis_quant, jpeg->overshoot_deringing,
|
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( -1 );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
|
@ -266,7 +267,6 @@ vips_foreign_save_jpeg_target_class_init(
|
||||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||||
G_STRUCT_OFFSET( VipsForeignSaveJpegTarget, target ),
|
G_STRUCT_OFFSET( VipsForeignSaveJpegTarget, target ),
|
||||||
VIPS_TYPE_TARGET );
|
VIPS_TYPE_TARGET );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -307,7 +307,7 @@ vips_foreign_save_jpeg_file_build( VipsObject *object )
|
||||||
jpeg->Q, jpeg->profile, jpeg->optimize_coding,
|
jpeg->Q, jpeg->profile, jpeg->optimize_coding,
|
||||||
jpeg->interlace, save->strip, jpeg->no_subsample,
|
jpeg->interlace, save->strip, jpeg->no_subsample,
|
||||||
jpeg->trellis_quant, jpeg->overshoot_deringing,
|
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 );
|
VIPS_UNREF( target );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
@ -377,7 +377,7 @@ vips_foreign_save_jpeg_buffer_build( VipsObject *object )
|
||||||
jpeg->Q, jpeg->profile, jpeg->optimize_coding,
|
jpeg->Q, jpeg->profile, jpeg->optimize_coding,
|
||||||
jpeg->interlace, save->strip, jpeg->no_subsample,
|
jpeg->interlace, save->strip, jpeg->no_subsample,
|
||||||
jpeg->trellis_quant, jpeg->overshoot_deringing,
|
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 );
|
VIPS_UNREF( target );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
@ -450,7 +450,7 @@ vips_foreign_save_jpeg_mime_build( VipsObject *object )
|
||||||
jpeg->Q, jpeg->profile, jpeg->optimize_coding,
|
jpeg->Q, jpeg->profile, jpeg->optimize_coding,
|
||||||
jpeg->interlace, save->strip, jpeg->no_subsample,
|
jpeg->interlace, save->strip, jpeg->no_subsample,
|
||||||
jpeg->trellis_quant, jpeg->overshoot_deringing,
|
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 );
|
VIPS_UNREF( target );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
|
|
@ -166,7 +166,7 @@ int vips__jpeg_write_target( VipsImage *in, VipsTarget *target,
|
||||||
gboolean optimize_coding, gboolean progressive, gboolean strip,
|
gboolean optimize_coding, gboolean progressive, gboolean strip,
|
||||||
gboolean no_subsample, gboolean trellis_quant,
|
gboolean no_subsample, gboolean trellis_quant,
|
||||||
gboolean overshoot_deringing, gboolean optimize_scans,
|
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,
|
int vips__jpeg_read_source( VipsSource *source, VipsImage *out,
|
||||||
gboolean header_only, int shrink, int fail, gboolean autorotate );
|
gboolean header_only, int shrink, int fail, gboolean autorotate );
|
||||||
|
|
|
@ -479,9 +479,9 @@ write_jpeg_block( VipsRegion *region, VipsRect *area, void *a )
|
||||||
static int
|
static int
|
||||||
write_vips( Write *write, int qfac, const char *profile,
|
write_vips( Write *write, int qfac, const char *profile,
|
||||||
gboolean optimize_coding, gboolean progressive, gboolean strip,
|
gboolean optimize_coding, gboolean progressive, gboolean strip,
|
||||||
gboolean no_subsample, gboolean trellis_quant,
|
gboolean trellis_quant, gboolean overshoot_deringing,
|
||||||
gboolean overshoot_deringing, gboolean optimize_scans, int quant_table,
|
gboolean optimize_scans, int quant_table,
|
||||||
gboolean force_subsample)
|
VipsForeignJpegSubsample subsample_mode)
|
||||||
{
|
{
|
||||||
VipsImage *in;
|
VipsImage *in;
|
||||||
J_COLOR_SPACE space;
|
J_COLOR_SPACE space;
|
||||||
|
@ -628,18 +628,24 @@ write_vips( Write *write, int qfac, const char *profile,
|
||||||
if( progressive )
|
if( progressive )
|
||||||
jpeg_simple_progression( &write->cinfo );
|
jpeg_simple_progression( &write->cinfo );
|
||||||
|
|
||||||
/* Turn off chroma subsampling. Follow IM and do it automatically for
|
switch (subsample_mode) {
|
||||||
* high Q.
|
case VIPS_FOREIGN_JPEG_SUBSAMPLE_ON:
|
||||||
*/
|
break;
|
||||||
if( !force_subsample && (
|
case VIPS_FOREIGN_JPEG_SUBSAMPLE_AUTO:
|
||||||
no_subsample ||
|
/* Turn off chroma subsampling. Follow IM and do it automatically for
|
||||||
qfac >= 90 )) {
|
* high Q.
|
||||||
int i;
|
*/
|
||||||
|
if( qfac < 90 ) {
|
||||||
for( i = 0; i < in->Bands; i++ ) {
|
break;
|
||||||
write->cinfo.comp_info[i].h_samp_factor = 1;
|
}
|
||||||
write->cinfo.comp_info[i].v_samp_factor = 1;
|
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.
|
/* Don't write the APP0 JFIF headers if we are stripping.
|
||||||
|
@ -778,7 +784,7 @@ vips__jpeg_write_target( VipsImage *in, VipsTarget *target,
|
||||||
gboolean optimize_coding, gboolean progressive,
|
gboolean optimize_coding, gboolean progressive,
|
||||||
gboolean strip, gboolean no_subsample, gboolean trellis_quant,
|
gboolean strip, gboolean no_subsample, gboolean trellis_quant,
|
||||||
gboolean overshoot_deringing, gboolean optimize_scans, int quant_table,
|
gboolean overshoot_deringing, gboolean optimize_scans, int quant_table,
|
||||||
gboolean force_subsample)
|
VipsForeignJpegSubsample subsample_mode)
|
||||||
{
|
{
|
||||||
Write *write;
|
Write *write;
|
||||||
|
|
||||||
|
@ -800,12 +806,18 @@ vips__jpeg_write_target( VipsImage *in, VipsTarget *target,
|
||||||
*/
|
*/
|
||||||
target_dest( &write->cinfo, target );
|
target_dest( &write->cinfo, target );
|
||||||
|
|
||||||
|
/* Retain old behavior for now
|
||||||
|
*/
|
||||||
|
if( no_subsample ) {
|
||||||
|
subsample_mode = VIPS_FOREIGN_JPEG_SUBSAMPLE_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
/* Convert! Write errors come back here as an error return.
|
/* Convert! Write errors come back here as an error return.
|
||||||
*/
|
*/
|
||||||
if( write_vips( write,
|
if( write_vips( write,
|
||||||
Q, profile, optimize_coding, progressive, strip, no_subsample,
|
Q, profile, optimize_coding, progressive, strip,
|
||||||
trellis_quant, overshoot_deringing, optimize_scans,
|
trellis_quant, overshoot_deringing, optimize_scans,
|
||||||
quant_table, force_subsample ) ) {
|
quant_table, subsample_mode ) ) {
|
||||||
write_destroy( write );
|
write_destroy( write );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,8 @@ GType vips_foreign_flags_get_type (void) G_GNUC_CONST;
|
||||||
#define VIPS_TYPE_FOREIGN_FLAGS (vips_foreign_flags_get_type())
|
#define VIPS_TYPE_FOREIGN_FLAGS (vips_foreign_flags_get_type())
|
||||||
GType vips_saveable_get_type (void) G_GNUC_CONST;
|
GType vips_saveable_get_type (void) G_GNUC_CONST;
|
||||||
#define VIPS_TYPE_SAVEABLE (vips_saveable_get_type())
|
#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;
|
GType vips_foreign_webp_preset_get_type (void) G_GNUC_CONST;
|
||||||
#define VIPS_TYPE_FOREIGN_WEBP_PRESET (vips_foreign_webp_preset_get_type())
|
#define VIPS_TYPE_FOREIGN_WEBP_PRESET (vips_foreign_webp_preset_get_type())
|
||||||
GType vips_foreign_tiff_compression_get_type (void) G_GNUC_CONST;
|
GType vips_foreign_tiff_compression_get_type (void) G_GNUC_CONST;
|
||||||
|
|
|
@ -364,6 +364,18 @@ int vips_vipssave( VipsImage *in, const char *filename, ... )
|
||||||
int vips_openslideload( const char *filename, VipsImage **out, ... )
|
int vips_openslideload( const char *filename, VipsImage **out, ... )
|
||||||
__attribute__((sentinel));
|
__attribute__((sentinel));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* VipsForeignJpegSubsample:
|
||||||
|
* @VIPS_FOREIGN_JPEG_SUBSAMPLE_AUTO: default preset
|
||||||
|
* @VIPS_FOREIGN_JPEG_SUBSAMPLE_ON: always perform subsampling
|
||||||
|
* @VIPS_FOREIGN_JPEG_SUBSAMPLE_OFF: 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, ... )
|
int vips_jpegload( const char *filename, VipsImage **out, ... )
|
||||||
__attribute__((sentinel));
|
__attribute__((sentinel));
|
||||||
int vips_jpegload_buffer( void *buf, size_t len, VipsImage **out, ... )
|
int vips_jpegload_buffer( void *buf, size_t len, VipsImage **out, ... )
|
||||||
|
|
|
@ -499,6 +499,24 @@ vips_saveable_get_type( void )
|
||||||
return( etype );
|
return( etype );
|
||||||
}
|
}
|
||||||
GType
|
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 )
|
vips_foreign_webp_preset_get_type( void )
|
||||||
{
|
{
|
||||||
static GType etype = 0;
|
static GType etype = 0;
|
||||||
|
|
|
@ -259,14 +259,21 @@ class TestForeign:
|
||||||
im = pyvips.Image.new_from_file(JPEG_FILE)
|
im = pyvips.Image.new_from_file(JPEG_FILE)
|
||||||
|
|
||||||
# higher Q should mean a bigger buffer
|
# higher Q should mean a bigger buffer
|
||||||
b1 = im.jpegsave_buffer(Q=10)
|
q10 = im.jpegsave_buffer(Q=10)
|
||||||
b2 = im.jpegsave_buffer(Q=90)
|
q10_subsample_off = im.jpegsave_buffer(Q=10, subsample_mode=2)
|
||||||
assert len(b2) > len(b1)
|
q10_subsample_no = im.jpegsave_buffer(Q=10, no_subsample=1)
|
||||||
|
q10_subsample_no_and_subsample_mode_on = im.jpegsave_buffer(Q=10, no_subsample=1, subsample_mode=1)
|
||||||
|
q90 = im.jpegsave_buffer(Q=90)
|
||||||
|
assert len(q90) > len(q10)
|
||||||
|
assert len(q10_subsample_off) > len(q10)
|
||||||
|
assert len(q10_subsample_off) == len(q10_subsample_no)
|
||||||
|
assert len(q10_subsample_no_and_subsample_mode_on) == len(q10_subsample_no)
|
||||||
|
|
||||||
# force subsampling should result in smaller buffer
|
# force subsampling should result in smaller buffer
|
||||||
b1 = im.jpegsave_buffer(Q=90, force_subsample=True)
|
q90_subsample_on = im.jpegsave_buffer(Q=90, subsample_mode=1)
|
||||||
b2 = im.jpegsave_buffer(Q=90)
|
q90_subsample_auto = im.jpegsave_buffer(Q=90, subsample_mode=0)
|
||||||
assert len(b2) > len(b1)
|
assert len(q90) > len(q90_subsample_on)
|
||||||
|
assert len(q90) == len(q90_subsample_auto)
|
||||||
|
|
||||||
@skip_if_no("jpegload")
|
@skip_if_no("jpegload")
|
||||||
def test_truncated(self):
|
def test_truncated(self):
|
||||||
|
|
Loading…
Reference in New Issue