add a --linear option to vipsthumbnail
thanks to Nicolas for the prodding
This commit is contained in:
parent
bc0c4f60d6
commit
8dfe4611d2
@ -18,6 +18,7 @@
|
|||||||
- add vips_crop(), a synonym for vips_extract_area()
|
- add vips_crop(), a synonym for vips_extract_area()
|
||||||
- rename vips_gammacorrect() as vips_gamma(), now takes 1 / exp
|
- rename vips_gammacorrect() as vips_gamma(), now takes 1 / exp
|
||||||
- vips_gamma() works for any format
|
- vips_gamma() works for any format
|
||||||
|
- add --linear mode to vipsthumbnail
|
||||||
|
|
||||||
18/10/13 started 7.36.3
|
18/10/13 started 7.36.3
|
||||||
- fix compiler warnings in ubuntu 13.10
|
- fix compiler warnings in ubuntu 13.10
|
||||||
|
14
TODO
14
TODO
@ -1,6 +1,16 @@
|
|||||||
- add a --linear option to vipsthumbnail
|
- vipsthumbnail could shrink-on-load openslide and pyr tiff as well?
|
||||||
|
|
||||||
also something to delete metadata?
|
- vipsthumbnail can use vips_conv() now and get rid of the INTMASK
|
||||||
|
|
||||||
|
- vips_icc_import() could offer XYZ as well as LAB? it'd save two conversions
|
||||||
|
in vipsthumbnail
|
||||||
|
|
||||||
|
vips_icc_export() would need to be able to accept both types as well
|
||||||
|
|
||||||
|
at the moment, icc_export() assumes LAB, it needs a vips_colourspace() on
|
||||||
|
the input to do an automatic transform for you see vips_dE00() etc.
|
||||||
|
|
||||||
|
- jpegsave needs a --strip option
|
||||||
|
|
||||||
- look again at gcc auto-vectorisation, what would we need to do to use this?
|
- look again at gcc auto-vectorisation, what would we need to do to use this?
|
||||||
|
|
||||||
|
@ -97,6 +97,12 @@ should be supplied with the
|
|||||||
.B --oprofile
|
.B --oprofile
|
||||||
option.
|
option.
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.B -a, --linear
|
||||||
|
Process in linear space. The input image is transformed to CIE XYZ on load,
|
||||||
|
shrunk, and then converted back to device space for write. This can increase
|
||||||
|
quality at the cost of processing time.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
.B -d, --delete
|
.B -d, --delete
|
||||||
Delete the output profile from the image. This can save a small amount of
|
Delete the output profile from the image. This can save a small amount of
|
||||||
|
@ -38,6 +38,8 @@
|
|||||||
* 10/7/13
|
* 10/7/13
|
||||||
* - rewrite for vips8
|
* - rewrite for vips8
|
||||||
* - handle embedded jpeg thumbnails
|
* - handle embedded jpeg thumbnails
|
||||||
|
* 12/11/13
|
||||||
|
* - add --linear option
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
@ -62,6 +64,7 @@ static char *export_profile = NULL;
|
|||||||
static char *import_profile = NULL;
|
static char *import_profile = NULL;
|
||||||
static char *convolution_mask = "mild";
|
static char *convolution_mask = "mild";
|
||||||
static gboolean delete_profile = FALSE;
|
static gboolean delete_profile = FALSE;
|
||||||
|
static gboolean linear_processing = FALSE;
|
||||||
|
|
||||||
/* Deprecated and unused.
|
/* Deprecated and unused.
|
||||||
*/
|
*/
|
||||||
@ -94,6 +97,9 @@ static GOptionEntry options[] = {
|
|||||||
G_OPTION_ARG_STRING, &import_profile,
|
G_OPTION_ARG_STRING, &import_profile,
|
||||||
N_( "import untagged images with PROFILE" ),
|
N_( "import untagged images with PROFILE" ),
|
||||||
N_( "PROFILE" ) },
|
N_( "PROFILE" ) },
|
||||||
|
{ "linear", 'a', 0,
|
||||||
|
G_OPTION_ARG_NONE, &linear_processing,
|
||||||
|
N_( "process in linear space" ), NULL },
|
||||||
{ "delete", 'd', 0,
|
{ "delete", 'd', 0,
|
||||||
G_OPTION_ARG_NONE, &delete_profile,
|
G_OPTION_ARG_NONE, &delete_profile,
|
||||||
N_( "delete profile from exported image" ), NULL },
|
N_( "delete profile from exported image" ), NULL },
|
||||||
@ -154,7 +160,13 @@ thumbnail_find_jpegshrink( VipsImage *im )
|
|||||||
{
|
{
|
||||||
int shrink = calculate_shrink( im->Xsize, im->Ysize, NULL );
|
int shrink = calculate_shrink( im->Xsize, im->Ysize, NULL );
|
||||||
|
|
||||||
if( shrink >= 8 )
|
/* We can't use pre-shrunk images in linear mode. libjpeg shrinks in Y
|
||||||
|
* (of YCbCR), not linear space.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if( linear_processing )
|
||||||
|
return( 1 );
|
||||||
|
else if( shrink >= 8 )
|
||||||
return( 8 );
|
return( 8 );
|
||||||
else if( shrink >= 4 )
|
else if( shrink >= 4 )
|
||||||
return( 4 );
|
return( 4 );
|
||||||
@ -226,6 +238,9 @@ thumbnail_open( VipsObject *thumbnail, const char *filename )
|
|||||||
|
|
||||||
vips_info( "vipsthumbnail", "thumbnailing %s", filename );
|
vips_info( "vipsthumbnail", "thumbnailing %s", filename );
|
||||||
|
|
||||||
|
if( linear_processing )
|
||||||
|
vips_info( "vipsthumbnail", "linear mode" );
|
||||||
|
|
||||||
if( !(loader = vips_foreign_find_load( filename )) )
|
if( !(loader = vips_foreign_find_load( filename )) )
|
||||||
return( NULL );
|
return( NULL );
|
||||||
|
|
||||||
@ -291,6 +306,8 @@ thumbnail_shrink( VipsObject *thumbnail, VipsImage *in,
|
|||||||
VipsInterpolate *interp, INTMASK *sharpen )
|
VipsInterpolate *interp, INTMASK *sharpen )
|
||||||
{
|
{
|
||||||
VipsImage **t = (VipsImage **) vips_object_local_array( thumbnail, 10 );
|
VipsImage **t = (VipsImage **) vips_object_local_array( thumbnail, 10 );
|
||||||
|
VipsInterpretation interpretation = linear_processing ?
|
||||||
|
VIPS_INTERPRETATION_XYZ : VIPS_INTERPRETATION_sRGB;
|
||||||
|
|
||||||
int shrink;
|
int shrink;
|
||||||
double residual;
|
double residual;
|
||||||
@ -298,30 +315,54 @@ thumbnail_shrink( VipsObject *thumbnail, VipsImage *in,
|
|||||||
int tile_height;
|
int tile_height;
|
||||||
int nlines;
|
int nlines;
|
||||||
|
|
||||||
/* Unpack the two coded formats we support.
|
/* RAD needs special unpacking.
|
||||||
*/
|
*/
|
||||||
if( in->Coding == VIPS_CODING_LABQ ) {
|
if( in->Coding == IM_CODING_RAD ) {
|
||||||
vips_info( "vipsthumbnail", "unpacking LAB to RGB" );
|
|
||||||
|
|
||||||
if( vips_colourspace( in, &t[0],
|
|
||||||
VIPS_INTERPRETATION_sRGB, NULL ) )
|
|
||||||
return( NULL );
|
|
||||||
|
|
||||||
in = t[0];
|
|
||||||
}
|
|
||||||
else if( in->Coding == IM_CODING_RAD ) {
|
|
||||||
vips_info( "vipsthumbnail", "unpacking Rad to float" );
|
vips_info( "vipsthumbnail", "unpacking Rad to float" );
|
||||||
|
|
||||||
/* rad is scrgb.
|
/* rad is scrgb.
|
||||||
*/
|
*/
|
||||||
if( vips_rad2float( in, &t[1], NULL ) ||
|
if( vips_rad2float( in, &t[0], NULL ) )
|
||||||
vips_colourspace( t[1], &t[2],
|
return( NULL );
|
||||||
VIPS_INTERPRETATION_sRGB, NULL ) )
|
in = t[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In linear mode, we import right at the start.
|
||||||
|
*
|
||||||
|
* This is only going to work for images in device space. If you have
|
||||||
|
* an image in PCS which also has an attached profile, strange things
|
||||||
|
* will happen.
|
||||||
|
*/
|
||||||
|
if( linear_processing &&
|
||||||
|
in->Coding == VIPS_CODING_NONE &&
|
||||||
|
(in->BandFmt == VIPS_FORMAT_UCHAR ||
|
||||||
|
in->BandFmt == VIPS_FORMAT_USHORT) &&
|
||||||
|
(vips_image_get_typeof( in, VIPS_META_ICC_NAME ) ||
|
||||||
|
import_profile) ) {
|
||||||
|
if( vips_image_get_typeof( in, VIPS_META_ICC_NAME ) )
|
||||||
|
vips_info( "vipsthumbnail",
|
||||||
|
"importing with embedded profile" );
|
||||||
|
else
|
||||||
|
vips_info( "vipsthumbnail",
|
||||||
|
"importing with profile %s", import_profile );
|
||||||
|
|
||||||
|
if( vips_icc_import( in, &t[1],
|
||||||
|
"input_profile", import_profile,
|
||||||
|
"embedded", TRUE,
|
||||||
|
NULL ) )
|
||||||
return( NULL );
|
return( NULL );
|
||||||
|
|
||||||
in = t[2];
|
in = t[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* To the processing colourspace. This will unpack LABQ as well.
|
||||||
|
*/
|
||||||
|
vips_info( "vipsthumbnail", "converting to processing space %s",
|
||||||
|
vips_enum_nick( VIPS_TYPE_INTERPRETATION, interpretation ) );
|
||||||
|
if( vips_colourspace( in, &t[2], interpretation, NULL ) )
|
||||||
|
return( NULL );
|
||||||
|
in = t[2];
|
||||||
|
|
||||||
shrink = calculate_shrink( in->Xsize, in->Ysize, &residual );
|
shrink = calculate_shrink( in->Xsize, in->Ysize, &residual );
|
||||||
|
|
||||||
vips_info( "vipsthumbnail", "integer shrink by %d", shrink );
|
vips_info( "vipsthumbnail", "integer shrink by %d", shrink );
|
||||||
@ -368,24 +409,33 @@ thumbnail_shrink( VipsObject *thumbnail, VipsImage *in,
|
|||||||
vips_info( "vipsthumbnail", "%s interpolation",
|
vips_info( "vipsthumbnail", "%s interpolation",
|
||||||
VIPS_OBJECT_GET_CLASS( interp )->nickname );
|
VIPS_OBJECT_GET_CLASS( interp )->nickname );
|
||||||
|
|
||||||
/* If we are upsampling, don't sharpen, since nearest looks dumb
|
/* Colour management.
|
||||||
* sharpened.
|
*
|
||||||
|
* In linear mode, just export. In device space mode, do a combined
|
||||||
|
* import/export to transform to the target space.
|
||||||
*/
|
*/
|
||||||
if( shrink >= 1 &&
|
if( linear_processing ) {
|
||||||
residual <= 1.0 &&
|
if( export_profile ||
|
||||||
sharpen ) {
|
vips_image_get_typeof( in, VIPS_META_ICC_NAME ) ) {
|
||||||
vips_info( "vipsthumbnail", "sharpening thumbnail" );
|
vips_info( "vipsthumbnail",
|
||||||
t[6] = vips_image_new();
|
"exporting to device space with a profile" );
|
||||||
if( im_conv( in, t[6], sharpen ) )
|
if( vips_colourspace( in, &t[6],
|
||||||
|
VIPS_INTERPRETATION_LAB, NULL ) ||
|
||||||
|
vips_icc_export( t[6], &t[7],
|
||||||
|
"output_profile", export_profile,
|
||||||
|
NULL ) )
|
||||||
|
return( NULL );
|
||||||
|
in = t[7];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vips_info( "vipsthumbnail", "converting to sRGB" );
|
||||||
|
if( vips_colourspace( in, &t[6],
|
||||||
|
VIPS_INTERPRETATION_sRGB, NULL ) )
|
||||||
return( NULL );
|
return( NULL );
|
||||||
in = t[6];
|
in = t[6];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/* Colour management: we can transform the image if we have an output
|
else if( export_profile &&
|
||||||
* profile and an input profile. The input profile can be in the
|
|
||||||
* image, or if there is no profile there, supplied by the user.
|
|
||||||
*/
|
|
||||||
if( export_profile &&
|
|
||||||
(vips_image_get_typeof( in, VIPS_META_ICC_NAME ) ||
|
(vips_image_get_typeof( in, VIPS_META_ICC_NAME ) ||
|
||||||
import_profile) ) {
|
import_profile) ) {
|
||||||
if( vips_image_get_typeof( in, VIPS_META_ICC_NAME ) )
|
if( vips_image_get_typeof( in, VIPS_META_ICC_NAME ) )
|
||||||
@ -398,13 +448,26 @@ thumbnail_shrink( VipsObject *thumbnail, VipsImage *in,
|
|||||||
vips_info( "vipsthumbnail",
|
vips_info( "vipsthumbnail",
|
||||||
"exporting with profile %s", export_profile );
|
"exporting with profile %s", export_profile );
|
||||||
|
|
||||||
if( vips_icc_transform( in, &t[7], export_profile,
|
if( vips_icc_transform( in, &t[6], export_profile,
|
||||||
"input_profile", import_profile,
|
"input_profile", import_profile,
|
||||||
"embedded", TRUE,
|
"embedded", TRUE,
|
||||||
NULL ) )
|
NULL ) )
|
||||||
return( NULL );
|
return( NULL );
|
||||||
|
|
||||||
in = t[7];
|
in = t[6];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we are upsampling, don't sharpen, since nearest looks dumb
|
||||||
|
* sharpened.
|
||||||
|
*/
|
||||||
|
if( shrink >= 1 &&
|
||||||
|
residual <= 1.0 &&
|
||||||
|
sharpen ) {
|
||||||
|
vips_info( "vipsthumbnail", "sharpening thumbnail" );
|
||||||
|
t[8] = vips_image_new();
|
||||||
|
if( im_conv( in, t[8], sharpen ) )
|
||||||
|
return( NULL );
|
||||||
|
in = t[8];
|
||||||
}
|
}
|
||||||
|
|
||||||
if( delete_profile &&
|
if( delete_profile &&
|
||||||
|
Loading…
Reference in New Issue
Block a user