all done, I think
This commit is contained in:
parent
e958de7814
commit
2fa3736722
@ -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
32
TODO
@ -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?
|
||||
|
@ -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())
|
||||
|
@ -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));
|
||||
|
@ -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 )
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user