all done, I think

This commit is contained in:
John Cupitt 2017-01-06 13:43:43 +00:00
parent e958de7814
commit 2fa3736722
9 changed files with 211 additions and 92 deletions

View File

@ -19,6 +19,8 @@
VIPS_LIBRARY_AGE
- better support for bscale / bzero in fits images
- deprecate vips_warn() / vips_info(); use g_warning() / g_info() instead
- vipsthumbnail supports much fancier geometry strings
- vips_thumbnail() has new @size option
8/12/16 started 8.4.5
- allow libgsf-1.14.26 to help centos, thanks tdiprima

32
TODO
View File

@ -1,3 +1,35 @@
- </>
convert k2.jpg -resize "100x100<" x.jpg
downsize, ie. factor < 1
does not resize
convert x.jpg -resize "200x200<" y.jpg
upsize, ie. factor > 1
resizes
convert k2.jpg -resize "100x100>" x.jpg
downsize, ie. factor < 1
resizes
convert x.jpg -resize "200x200>" y.jpg
upsize, ie. factor > 1
does not resize
so: < means only resize if input size is less than, > means only resize if
input size is > than
awkward to fit inside vipsthumbnail.c, since we'd have to copy/paste all the
resize calcs
have to add another param to thumbnail ... up or down, only up, only down
- vipsdisp-tiny makes stripes if the image is not tagged correctly
is one of the colourspace functions not reading format?

View File

@ -9,6 +9,8 @@ G_BEGIN_DECLS
/* enumerations from "../../../libvips/include/vips/resample.h" */
GType vips_kernel_get_type (void) G_GNUC_CONST;
#define VIPS_TYPE_KERNEL (vips_kernel_get_type())
GType vips_size_get_type (void) G_GNUC_CONST;
#define VIPS_TYPE_SIZE (vips_size_get_type())
/* enumerations from "../../../libvips/include/vips/foreign.h" */
GType vips_foreign_flags_get_type (void) G_GNUC_CONST;
#define VIPS_TYPE_FOREIGN_FLAGS (vips_foreign_flags_get_type())

View File

@ -47,6 +47,13 @@ typedef enum {
VIPS_KERNEL_LAST
} VipsKernel;
typedef enum {
VIPS_SIZE_BOTH,
VIPS_SIZE_UP,
VIPS_SIZE_DOWN,
VIPS_SIZE_LAST
} VipsSize;
int vips_shrink( VipsImage *in, VipsImage **out,
double hshrink, double vshrink, ... )
__attribute__((sentinel));

View File

@ -26,6 +26,25 @@ vips_kernel_get_type( void )
return( etype );
}
GType
vips_size_get_type( void )
{
static GType etype = 0;
if( etype == 0 ) {
static const GEnumValue values[] = {
{VIPS_SIZE_BOTH, "VIPS_SIZE_BOTH", "both"},
{VIPS_SIZE_UP, "VIPS_SIZE_UP", "up"},
{VIPS_SIZE_DOWN, "VIPS_SIZE_DOWN", "down"},
{VIPS_SIZE_LAST, "VIPS_SIZE_LAST", "last"},
{0, NULL, NULL}
};
etype = g_enum_register_static( "VipsSize", values );
}
return( etype );
}
/* enumerations from "../../libvips/include/vips/foreign.h" */
GType
vips_foreign_flags_get_type( void )

View File

@ -82,6 +82,18 @@
* Finally, vips_mapim() can apply arbitrary 2D image transforms to an image.
*/
/**
* VipsSize:
* @VIPS_SIZE_BOTH: size both up and down
* @VIPS_SIZE_UP: only upsize
* @VIPS_SIZE_DOWN: only downsize
*
* Controls whether an operation should upsize, downsize, or both up and
* downsize.
*
* See also: vips_thumbnail().
*/
G_DEFINE_ABSTRACT_TYPE( VipsResample, vips_resample, VIPS_TYPE_OPERATION );
static int

View File

@ -3,6 +3,8 @@
*
* 2/11/16
* - from vipsthumbnail.c
* 6/1/17
* - add @size parameter
*/
/*
@ -68,6 +70,7 @@ typedef struct _VipsThumbnail {
VipsImage *out;
int width;
int height;
VipsSize size;
gboolean auto_rotate;
gboolean crop;
@ -122,6 +125,7 @@ vips_thumbnail_calculate_shrink( VipsThumbnail *thumbnail,
input_width : input_height;
VipsDirection direction;
double shrink;
/* Calculate the horizontal and vertical shrink we'd need to fit the
* image to the bounding box, and pick the biggest.
@ -145,8 +149,17 @@ vips_thumbnail_calculate_shrink( VipsThumbnail *thumbnail,
direction = VIPS_DIRECTION_HORIZONTAL;
}
return( direction == VIPS_DIRECTION_HORIZONTAL ?
horizontal : vertical );
shrink = direction == VIPS_DIRECTION_HORIZONTAL ?
horizontal : vertical;
/* Restrict to only upsize, only downsize, or both.
*/
if( thumbnail->size == VIPS_SIZE_UP )
shrink = VIPS_MIN( 1, shrink );
if( thumbnail->size == VIPS_SIZE_DOWN )
shrink = VIPS_MAX( 1, shrink );
return( shrink );
}
/* Find the best jpeg preload shrink.
@ -497,35 +510,42 @@ vips_thumbnail_class_init( VipsThumbnailClass *class )
G_STRUCT_OFFSET( VipsThumbnail, height ),
1, VIPS_MAX_COORD, 1 );
VIPS_ARG_BOOL( class, "auto_rotate", 114,
VIPS_ARG_ENUM( class, "size", 114,
_( "size" ),
_( "Only upsize, only downsize, or both" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsThumbnail, size ),
VIPS_TYPE_SIZE, VIPS_SIZE_BOTH );
VIPS_ARG_BOOL( class, "auto_rotate", 115,
_( "Auto rotate" ),
_( "Use orientation tags to rotate image upright" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsThumbnail, auto_rotate ),
TRUE );
VIPS_ARG_BOOL( class, "crop", 115,
VIPS_ARG_BOOL( class, "crop", 116,
_( "Crop" ),
_( "Reduce to fill target rectangle, then crop" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsThumbnail, crop ),
FALSE );
VIPS_ARG_BOOL( class, "linear", 116,
VIPS_ARG_BOOL( class, "linear", 117,
_( "Linear" ),
_( "Reduce in linear light" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsThumbnail, linear ),
FALSE );
VIPS_ARG_STRING( class, "import_profile", 117,
VIPS_ARG_STRING( class, "import_profile", 118,
_( "Import profile" ),
_( "Fallback import profile" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsThumbnail, import_profile ),
NULL );
VIPS_ARG_STRING( class, "export_profile", 118,
VIPS_ARG_STRING( class, "export_profile", 119,
_( "Export profile" ),
_( "Fallback export profile" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
@ -643,6 +663,7 @@ vips_thumbnail_file_init( VipsThumbnailFile *file )
* Optional arguments:
*
* * @height: %gint, target height in pixels
* * @size: #VipsSize, upsize, downsize or both
* * @auto_rotate: %gboolean, rotate upright using orientation tag
* * @crop: %gboolean, shrink and crop to fill target
* * @linear: %gboolean, perform shrink in linear light
@ -658,11 +679,18 @@ vips_thumbnail_file_init( VipsThumbnailFile *file )
* See vips_thumbnail_buffer() to thumbnail from a memory source.
*
* The output image will fit within a square of size @width x @width. You can
* specify a height with the @height option.
* specify a separate height with the @height option.
*
* If you set @crop, then the output image will fill the whole of the @width x
* @height rectangle, with any excess cropped away.
*
* Normally the operation will upsize or downsize as required. If @size is set
* to #VIPS_SIZE_UP, the operation will only upsize and will just
* copy if asked to downsize.
* If @size is set
* to #VIPS_SIZE_DOWN, the operation will only downsize and will just
* copy if asked to upsize.
*
* Normally any orientation tags on the input image (such as EXIF tags) are
* interpreted to rotate the image upright. If you set @auto_rotate to %FALSE,
* these tags will not be interpreted.
@ -803,6 +831,7 @@ vips_thumbnail_buffer_init( VipsThumbnailBuffer *buffer )
* Optional arguments:
*
* * @height: %gint, target height in pixels
* * @size: #VipsSize, upsize, downsize or both
* * @auto_rotate: %gboolean, rotate upright using orientation tag
* * @crop: %gboolean, shrink and crop to fill target
* * @linear: %gboolean, perform shrink in linear light

View File

@ -26,7 +26,7 @@ and write thumbnails to the files
and
.B tn_jim.jpg.
$ vipsthumbnail --size=64 -f thumbnails/%s.png fred.jpg
$ vipsthumbnail --size=64 -o thumbnails/%s.png fred.jpg
will read image file
.B fred.jpg
@ -42,10 +42,12 @@ x
.B N
pixels. You can use MxN to specify a rectangular bounding box.
The image is shrunk so that it just fits within this area, images
which are smaller than this are expanded.
which are smaller than this are expanded. Use "xN" or "Mx" to just resize on
one axis. Append "<" to only resize if the input image is smaller than the
target, append ">" to only resize if the input image is larger than the target.
.TP
.B -f FORMAT, --format=FORMAT
.B -o FORMAT, --output=FORMAT
Set the output format string. The input filename has any file type suffix
removed, then that value is substitued into
.B FORMAT
@ -65,27 +67,6 @@ prepended. You can add format options too, for example
.B tn_%s.jpg[Q=20]
will write JPEG images with Q set to 20.
.TP
.B -p I, --interpolator=I
Resample with interpolator
.B I.
Use
.B vips --list classes
to see a list of valid interpolators. The default is
.B bilinear.
.TP
.B -r, --sharpen=none|mild|MASKFILE
Images can look a little soft after shrinking. This option lets you specify
a sharpening mask. Use "none" to disable sharpening, or "mild" to sharpen
lightly, or give the filename of a custom mask file to use. The default is
"mild". The built-in mild sharpen mask is:
3 3 24 0
-1 -1 -1
-1 32 -1
-1 -1 -1
.TP
.B -e PROFILE, --eprofile=PROFILE
Export thumbnails with this ICC profile. Images are only colour-transformed if
@ -114,10 +95,12 @@ Delete the output profile from the image. This can save a small amount of
space.
.TP
.B -v, --verbose
.B vipsthumbnail(1)
normally runs silently, except for warning and error messages. This option
makes it print a list of the operations it performs on each image.
.B -t, --rotate
Auto-rotate images using EXIF orientation tags.
.TP
.B -a, --linear
Shrink images in linear light colour space. This can be much slower.
.SH RETURN VALUE
returns 0 on success and non-zero on error. Error can mean one or more

View File

@ -85,6 +85,11 @@
* - use scRGB as the working space in linear mode
* 15/8/16
* - can now remove 0.1 rounding adjustment
* 2/11/16
* - use vips_thumbnail(), most code moved there
* 6/1/17
* - fancy geometry strings
* - support VipSize restrictions
*/
#ifdef HAVE_CONFIG_H
@ -108,6 +113,7 @@
static char *thumbnail_size = "128";
static int thumbnail_width = 128;
static int thumbnail_height = 128;
static VipsSize size_restriction = VIPS_SIZE_BOTH;
static char *output_format = "tn_%s.jpg";
static char *export_profile = NULL;
static char *import_profile = NULL;
@ -229,10 +235,11 @@ thumbnail_write( VipsObject *process, VipsImage *im, const char *filename )
static int
thumbnail_process( VipsObject *process, const char *filename )
{
VipsImage *in;
VipsImage *image;
if( vips_thumbnail( filename, &in, thumbnail_width,
if( vips_thumbnail( filename, &image, thumbnail_width,
"height", thumbnail_height,
"size", size_restriction,
"auto_rotate", rotate_image,
"crop", crop_image,
"linear", linear_processing,
@ -241,52 +248,103 @@ thumbnail_process( VipsObject *process, const char *filename )
NULL ) )
return( -1 );
if( thumbnail_write( process, in, filename ) ) {
g_object_unref( in );
if( thumbnail_write( process, image, filename ) ) {
g_object_unref( image );
return( -1 );
}
g_object_unref( in );
g_object_unref( image );
return( 0 );
}
/* Fetch a match_info string, NULL for "".
*/
static const char *
fetch_match( GMatchInfo *match_info, int n )
{
const char *str = g_match_info_fetch( match_info, n );
return( strcmp( str, "" ) == 0 ? NULL : str );
}
/* Parse a geometry string and set thumbnail_width and thumbnail_height.
*/
static int
thumbnail_parse_geometry( const char *geometry )
{
GRegEx *regex;
regex = g_regex_new( "^(\d+)? (x)? (\d+)? ([<>])?$",
G_REGEX_CASELESS | G_REGEX_EXTENDED, 0, NULL );
g_regex_match( regex, geometry, 0, &match_info );
if(
char *p;
/* Up to 'x'
int w, h;
GRegex *regex;
GMatchInfo *match_info;
gboolean handled;
handled = FALSE;
if( sscanf( geometry, "%d x %d <", &w, &h ) == 2 ) {
thumbnail_width = w;
thumbnail_height = h;
crop_image = FALSE;
regex = g_regex_new( "^(\\d+)? (x)? (\\d+)? ([<>])?$",
G_REGEX_CASELESS | G_REGEX_EXTENDED, 0, NULL );
g_regex_match( regex, geometry, 0, &match_info );
if( g_match_info_matches( match_info ) ) {
const char *w = fetch_match( match_info, 1 );
const char *x = fetch_match( match_info, 2 );
const char *h = fetch_match( match_info, 3 );
const char *s = fetch_match( match_info, 4 );
/* If --crop is set, both width and height must be specified,
* since we'll need a complete bounding box to fill.
*/
if( crop_image && x && (!w || !h) ) {
vips_error( "thumbnail",
"both width and height must be given if "
"--crop is enabled" );
return( -1 );
}
if( !x ) {
/* No "x" means we only allow a single number and it
* sets both width and height.
*/
if( w && !h ) {
thumbnail_width = thumbnail_height = atoi( w );
handled = TRUE;
}
if( !w && h ) {
thumbnail_width = thumbnail_height = atoi( h );
handled = TRUE;
}
}
else {
/* w or h missing means replace with a huuuge value
* to prevent reduction or enlargement in that axis.
*/
thumbnail_width = VIPS_MAX_COORD;
thumbnail_height = VIPS_MAX_COORD;
if( w ) {
thumbnail_width = atoi( w );
handled = TRUE;
}
if( h ) {
thumbnail_height = atoi( h );
handled = TRUE;
}
}
if( s && strcmp( s, ">" ) == 0 )
size_restriction = VIPS_SIZE_DOWN;
if( s && strcmp( s, "<" ) == 0 )
size_restriction = VIPS_SIZE_UP;
}
if( sscanf( geometry, "%d x %d >", &w, &h ) == 2 ) {
thumbnail_width = w;
thumbnail_height = h;
crop_image = TRUE;
g_match_info_free( match_info );
g_regex_unref( regex );
if( !handled ) {
vips_error( "thumbnail",
"unable to parse size \"%s\" -- "
"use eg. 128 or 200x300>", geometry );
return( -1 );
}
return( 0 );
}
int
@ -334,40 +392,15 @@ main( int argc, char **argv )
g_option_context_free( context );
/*
if( sscanf( thumbnail_size, "%d x %d",
&thumbnail_width, &thumbnail_height ) == 2 ) {
if( sscanf( thumbnail_size, "%d", &thumbnail_width ) != 1 )
vips_error_exit( "unable to parse size \"%s\" -- "
"use eg. 128 or 200x300", thumbnail_size );
if( thumbnail_parse_geometry( thumbnail_size ) )
vips_error_exit( NULL );
thumbnail_height = thumbnail_width;
}
*/
if( sscanf( thumbnail_size, "%d x %d",
&thumbnail_width, &thumbnail_height ) == 2 ) {
if( sscanf( thumbnail_size, "%d", &thumbnail_width ) != 1 )
vips_error_exit( "unable to parse size \"%s\" -- "
"use eg. 128 or 200x300", thumbnail_size );
thumbnail_height = thumbnail_width;
}
if( sscanf( thumbnail_size, "%d", &thumbnail_width ) != 1 )
thumbnail_height = thumbnail_width;
}
vips_error_exit( "unable to parse size \"%s\" -- "
"use eg. 128 or 200x300", thumbnail_size );
if( rotate_image ) {
#ifndef HAVE_EXIF
if( rotate_image )
g_warning( "%s",
_( "auto-rotate disabled: "
"libvips built without exif support" ) );
#endif /*!HAVE_EXIF*/
}
result = 0;