Merge branch 'master' into add-thumbnail-geometry
This commit is contained in:
commit
fb88d037fc
@ -19,8 +19,12 @@
|
||||
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
|
||||
- vipsthumbnail supports much fancier geometry strings, thanks tomasc
|
||||
- vips_thumbnail() has new @size option
|
||||
- fix --vips-cache-max etc.
|
||||
- add compute reordering, plus some new API to support it:
|
||||
vips_reorder_margin_hint() and vips_reorder_prepare_many(), thanks
|
||||
aferrero2707
|
||||
|
||||
8/12/16 started 8.4.5
|
||||
- allow libgsf-1.14.26 to help centos, thanks tdiprima
|
||||
|
@ -25,6 +25,8 @@ binding](http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/usin
|
||||
and a [command-line
|
||||
interface](http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/using-cli.html).
|
||||
Bindings are available for [Ruby](https://rubygems.org/gems/ruby-vips),
|
||||
[PHP](https://github.com/jcupitt/php-vips),
|
||||
[Go](https://github.com/davidbyttow/govips),
|
||||
JavaScript and others. There is full
|
||||
[documentation](http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/index.html).
|
||||
There are several GUIs as well, see the [VIPS
|
||||
|
36
TODO
36
TODO
@ -1,39 +1,3 @@
|
||||
- </>
|
||||
|
||||
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?
|
||||
|
||||
- not sure about utf8 error messages on win
|
||||
|
||||
- strange:
|
||||
|
@ -64,13 +64,11 @@ EXTRA_DIST = \
|
||||
|
||||
CLEANFILES =
|
||||
|
||||
all-local:
|
||||
while [ ! -f libvips.la ]; do sleep 1; done; sleep 1; \
|
||||
install-exec-hook:
|
||||
echo '/* This file is autogenerated, do not edit. */' > soname.h && \
|
||||
source libvips.la && \
|
||||
echo "#define VIPS_SONAME \"$$dlname\"" >> soname.h && \
|
||||
( cmp -s soname.h include/vips/soname.h || \
|
||||
cp soname.h include/vips ) && \
|
||||
cp soname.h $(DESTDIR)$(pkgincludedir) && \
|
||||
rm soname.h
|
||||
|
||||
-include $(INTROSPECTION_MAKEFILE)
|
||||
|
@ -516,11 +516,10 @@ vips_arithmetic_gen( VipsRegion *or,
|
||||
|
||||
/* Prepare all input regions and make buffer pointers.
|
||||
*/
|
||||
for( i = 0; ir[i]; i++ ) {
|
||||
if( vips_region_prepare( ir[i], r ) )
|
||||
return( -1 );
|
||||
if( vips_reorder_prepare_many( or->im, ir, r ) )
|
||||
return( -1 );
|
||||
for( i = 0; ir[i]; i++ )
|
||||
p[i] = (VipsPel *) VIPS_REGION_ADDR( ir[i], r->left, r->top );
|
||||
}
|
||||
p[i] = NULL;
|
||||
q = (VipsPel *) VIPS_REGION_ADDR( or, r->left, r->top );
|
||||
|
||||
|
@ -234,9 +234,8 @@ vips_colour_gen( VipsRegion *or,
|
||||
int i, y;
|
||||
VipsPel *p[MAX_INPUT_IMAGES], *q;
|
||||
|
||||
for( i = 0; ir[i]; i++ )
|
||||
if( vips_region_prepare( ir[i], r ) )
|
||||
return( -1 );
|
||||
if( vips_reorder_prepare_many( or->im, ir, r ) )
|
||||
return( -1 );
|
||||
|
||||
VIPS_GATE_START( "vips_colour_gen: work" );
|
||||
|
||||
|
@ -92,11 +92,10 @@ vips_bandary_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
|
||||
VipsPel *p[MAX_INPUT_IMAGES], *q;
|
||||
int y, i;
|
||||
|
||||
for( i = 0; i < bandary->n; i++ ) {
|
||||
if( vips_region_prepare( ir[i], r ) )
|
||||
return( -1 );
|
||||
if( vips_reorder_prepare_many( or->im, ir, r ) )
|
||||
return( -1 );
|
||||
for( i = 0; i < bandary->n; i++ )
|
||||
p[i] = VIPS_REGION_ADDR( ir[i], r->left, r->top );
|
||||
}
|
||||
p[i] = NULL;
|
||||
q = VIPS_REGION_ADDR( or, r->left, r->top );
|
||||
|
||||
|
@ -283,6 +283,9 @@ vips_blend_gen( VipsRegion *or, void *seq, void *client1, void *client2,
|
||||
else {
|
||||
/* Mix of set and clear ... ask for both then and else parts
|
||||
* and interleave.
|
||||
*
|
||||
* We can't use vips_reorder_prepare_many() since we always
|
||||
* want the c image first.
|
||||
*/
|
||||
if( vips_region_prepare( ir[0], r ) ||
|
||||
vips_region_prepare( ir[1], r ) )
|
||||
|
@ -113,6 +113,9 @@ vips_conv_build( VipsObject *object )
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
vips_reorder_margin_hint( convolution->out,
|
||||
convolution->M->Xsize * convolution->M->Ysize );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
@ -877,6 +877,9 @@ vips_convasep_build( VipsObject *object )
|
||||
convolution->out->Xoffset = 0;
|
||||
convolution->out->Yoffset = 0;
|
||||
|
||||
vips_reorder_margin_hint( convolution->out,
|
||||
convolution->M->Xsize * convolution->M->Ysize );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
@ -125,6 +125,9 @@ vips_correlation_build( VipsObject *object )
|
||||
correlation->in_ready, correlation ) )
|
||||
return( -1 );
|
||||
|
||||
vips_reorder_margin_hint( correlation->out,
|
||||
correlation->ref->Xsize * correlation->ref->Ysize );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
@ -121,8 +121,7 @@ vips_sharpen_generate( VipsRegion *or,
|
||||
|
||||
int x, y;
|
||||
|
||||
if( vips_region_prepare( in[0], r ) ||
|
||||
vips_region_prepare( in[1], r ) )
|
||||
if( vips_reorder_prepare_many( or->im, in, r ) )
|
||||
return( -1 );
|
||||
|
||||
VIPS_GATE_START( "vips_sharpen_generate: work" );
|
||||
|
@ -649,12 +649,11 @@ process_region( VipsRegion *or, void *seq, void *a, void *b )
|
||||
|
||||
/* Prepare all input regions and make buffer pointers.
|
||||
*/
|
||||
for( i = 0; ir[i]; i++ ) {
|
||||
if( vips_region_prepare( ir[i], &or->valid ) )
|
||||
return( -1 );
|
||||
if( vips_reorder_prepare_many( or->im, ir, &or->valid ) )
|
||||
return( -1 );
|
||||
for( i = 0; ir[i]; i++ )
|
||||
p[i] = (PEL *) VIPS_REGION_ADDR( ir[i],
|
||||
or->valid.left, or->valid.top );
|
||||
}
|
||||
p[i] = NULL;
|
||||
q = (PEL *) VIPS_REGION_ADDR( or, or->valid.left, or->valid.top );
|
||||
|
||||
|
@ -160,7 +160,7 @@ vips_webp_writer_appendle( VipsWebPWriter *writer, uint32_t val, int n )
|
||||
unsigned char buf[4];
|
||||
int i;
|
||||
|
||||
g_assert( n < 4 );
|
||||
g_assert( n <= 4 );
|
||||
|
||||
for( i = 0; i < n; i++ ) {
|
||||
buf[i] = (unsigned char) (val & 0xff);
|
||||
@ -237,7 +237,18 @@ write_webp( WebPPicture *pic, VipsImage *in,
|
||||
WebPConfig config;
|
||||
webp_import import;
|
||||
|
||||
if ( !WebPConfigPreset( &config, get_preset( preset ), Q ) ) {
|
||||
if( !WebPConfigInit( &config ) ) {
|
||||
vips_error( "vips2webp",
|
||||
"%s", _( "config version error" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* These presets are only for lossy compression. There seems to be
|
||||
* separate API for lossless or near-lossless, see
|
||||
* WebPConfigLosslessPreset().
|
||||
*/
|
||||
if( !(lossless || near_lossless) &&
|
||||
!WebPConfigPreset( &config, get_preset( preset ), Q ) ) {
|
||||
vips_error( "vips2webp", "%s", _( "config version error" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
@ -280,6 +280,8 @@ vips_hist_local_build( VipsObject *object )
|
||||
local->out->Xoffset = 0;
|
||||
local->out->Yoffset = 0;
|
||||
|
||||
vips_reorder_margin_hint( local->out, local->width * local->height );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
@ -272,6 +272,8 @@ vips_stdif_build( VipsObject *object )
|
||||
stdif->out->Xoffset = 0;
|
||||
stdif->out->Yoffset = 0;
|
||||
|
||||
vips_reorder_margin_hint( stdif->out, stdif->width * stdif->height );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
@ -506,6 +506,12 @@ VipsImage **vips_array_image_get( VipsArrayImage *array, int *n );
|
||||
VipsImage **vips_value_get_array_image( const GValue *value, int *n );
|
||||
void vips_value_set_array_image( GValue *value, int n );
|
||||
|
||||
/* Defined in reorder.c, but really a function on image.
|
||||
*/
|
||||
int vips_reorder_prepare_many( VipsImage *image,
|
||||
struct _VipsRegion **regions, VipsRect *r );
|
||||
void vips_reorder_margin_hint( VipsImage *image, int margin );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus*/
|
||||
|
@ -94,11 +94,6 @@ extern int vips__info;
|
||||
*/
|
||||
extern char *vips__disc_threshold;
|
||||
|
||||
/* Cache size settings.
|
||||
*/
|
||||
extern char *vips__cache_max;
|
||||
extern char *vips__cache_max_mem;
|
||||
extern char *vips__cache_max_files;
|
||||
extern gboolean vips__cache_dump;
|
||||
extern gboolean vips__cache_trace;
|
||||
|
||||
@ -255,6 +250,9 @@ int vips__foreign_convert_saveable( VipsImage *in, VipsImage **ready,
|
||||
|
||||
int vips__image_intize( VipsImage *in, VipsImage **out );
|
||||
|
||||
void vips__reorder_init( void );
|
||||
int vips__reorder_set_input( VipsImage *image, VipsImage **in );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus*/
|
||||
|
@ -1,6 +1,7 @@
|
||||
noinst_LTLIBRARIES = libiofuncs.la
|
||||
|
||||
libiofuncs_la_SOURCES = \
|
||||
reorder.c \
|
||||
vipsmarshal.h \
|
||||
vipsmarshal.c \
|
||||
type.c \
|
||||
|
@ -67,9 +67,6 @@
|
||||
|
||||
/* Set by GOption from the command line, eg. "12m".
|
||||
*/
|
||||
char *vips__cache_max = NULL;
|
||||
char *vips__cache_max_mem = NULL;
|
||||
char *vips__cache_max_files = NULL;
|
||||
gboolean vips__cache_dump = FALSE;
|
||||
gboolean vips__cache_trace = FALSE;
|
||||
|
||||
@ -456,18 +453,6 @@ vips__cache_init( void )
|
||||
vips_cache_table = g_hash_table_new(
|
||||
(GHashFunc) vips_operation_hash,
|
||||
(GEqualFunc) vips_operation_equal );
|
||||
|
||||
if( vips__cache_max )
|
||||
vips_cache_max =
|
||||
vips__parse_size( vips__cache_max );
|
||||
|
||||
if( vips__cache_max_mem )
|
||||
vips_cache_max_mem =
|
||||
vips__parse_size( vips__cache_max_mem );
|
||||
|
||||
if( vips__cache_max_files )
|
||||
vips_cache_max_files =
|
||||
vips__parse_size( vips__cache_max_files );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -379,12 +379,23 @@ int
|
||||
vips_image_pipeline_array( VipsImage *image,
|
||||
VipsDemandStyle hint, VipsImage **in )
|
||||
{
|
||||
/* This function can be called more than once per output image. For
|
||||
* example, jpeg header load will call this once on ->out to set the
|
||||
* default hint, then later call it again to connect the output image
|
||||
* up to the real image.
|
||||
*
|
||||
* It's only ever called first time with in[0] == NULL and second time
|
||||
* with a real value for @in.
|
||||
*/
|
||||
vips__demand_hint_array( image, hint, in );
|
||||
|
||||
if( in[0] &&
|
||||
vips__image_copy_fields_array( image, in ) )
|
||||
return( -1 );
|
||||
|
||||
if( vips__reorder_set_input( image, in ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
@ -364,6 +364,10 @@ vips_init( const char *argv0 )
|
||||
*/
|
||||
vips__cache_init();
|
||||
|
||||
/* Recomp reordering system.
|
||||
*/
|
||||
vips__reorder_init();
|
||||
|
||||
/* Start up packages.
|
||||
*/
|
||||
(void) vips_system_get_type();
|
||||
@ -614,6 +618,33 @@ vips_lib_version_cb( const gchar *option_name, const gchar *value,
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
static gboolean
|
||||
vips_cache_max_cb( const gchar *option_name, const gchar *value,
|
||||
gpointer data, GError **error )
|
||||
{
|
||||
vips_cache_set_max( vips__parse_size( value ) );
|
||||
|
||||
return( TRUE );
|
||||
}
|
||||
|
||||
static gboolean
|
||||
vips_cache_max_memory_cb( const gchar *option_name, const gchar *value,
|
||||
gpointer data, GError **error )
|
||||
{
|
||||
vips_cache_set_max_mem( vips__parse_size( value ) );
|
||||
|
||||
return( TRUE );
|
||||
}
|
||||
|
||||
static gboolean
|
||||
vips_cache_max_files_cb( const gchar *option_name, const gchar *value,
|
||||
gpointer data, GError **error )
|
||||
{
|
||||
vips_cache_set_max_files( vips__parse_size( value ) );
|
||||
|
||||
return( TRUE );
|
||||
}
|
||||
|
||||
static GOptionEntry option_entries[] = {
|
||||
{ "vips-info", 0, G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
|
||||
G_OPTION_ARG_CALLBACK, (gpointer) &vips_lib_info_cb,
|
||||
@ -652,13 +683,13 @@ static GOptionEntry option_entries[] = {
|
||||
G_OPTION_ARG_NONE, &vips__vector_enabled,
|
||||
N_( "disable vectorised versions of operations" ), NULL },
|
||||
{ "vips-cache-max", 0, 0,
|
||||
G_OPTION_ARG_STRING, &vips__cache_max,
|
||||
G_OPTION_ARG_CALLBACK, (gpointer) &vips_cache_max_cb,
|
||||
N_( "cache at most N operations" ), "N" },
|
||||
{ "vips-cache-max-memory", 0, 0,
|
||||
G_OPTION_ARG_STRING, &vips__cache_max_mem,
|
||||
G_OPTION_ARG_CALLBACK, (gpointer) &vips_cache_max_memory_cb,
|
||||
N_( "cache at most N bytes in memory" ), "N" },
|
||||
{ "vips-cache-max-files", 0, 0,
|
||||
G_OPTION_ARG_STRING, &vips__cache_max_files,
|
||||
G_OPTION_ARG_CALLBACK, (gpointer) &vips_cache_max_files_cb,
|
||||
N_( "allow at most N open files" ), "N" },
|
||||
{ "vips-cache-trace", 0, 0,
|
||||
G_OPTION_ARG_NONE, &vips__cache_trace,
|
||||
|
368
libvips/iofuncs/reorder.c
Normal file
368
libvips/iofuncs/reorder.c
Normal file
@ -0,0 +1,368 @@
|
||||
/* reorder.c ... manage reorder reordering
|
||||
*
|
||||
* 11/1/17
|
||||
* - first version
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
This file is part of VIPS.
|
||||
|
||||
VIPS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
#define DEBUG
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/internal.h>
|
||||
#include <vips/debug.h>
|
||||
|
||||
/* Have one of these on every image, identified by a quark.
|
||||
*/
|
||||
typedef struct _VipsReorder {
|
||||
/* The image we are attached to.
|
||||
*/
|
||||
VipsImage *image;
|
||||
|
||||
/* The direct inputs to this image, so a copy of the array that is
|
||||
* passed to vips_image_pipeline_array(), and in the same order.
|
||||
* NULL-terminated.
|
||||
*
|
||||
* Score is the priority we give to the inputs as we de-dupe the source
|
||||
* arrays.
|
||||
*
|
||||
* The recomp order is the order we prepare regions in ... just make a
|
||||
* range then sort by score.
|
||||
*/
|
||||
int n_inputs;
|
||||
VipsImage **input;
|
||||
int *score;
|
||||
int *recomp_order;
|
||||
|
||||
/* Source images are images with no input images, so file load,
|
||||
* vips_black(), etc. NULL-terminated array.
|
||||
*
|
||||
* The cumulative margin is the total margin that has been added to
|
||||
* each source image up to this point in the pipeline.
|
||||
*/
|
||||
int n_sources;
|
||||
VipsImage **source;
|
||||
int *cumulative_margin;
|
||||
|
||||
} VipsReorder;
|
||||
|
||||
GQuark vips__image_reorder_quark = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
static void
|
||||
vips_reorder_print( VipsReorder *reorder )
|
||||
{
|
||||
int i;
|
||||
|
||||
printf( "vips_reorder_print: " );
|
||||
vips_object_print_name( VIPS_OBJECT( reorder->image ) );
|
||||
printf( "\n" );
|
||||
|
||||
printf( "n_inputs = %d\n", reorder->n_inputs );
|
||||
printf( " n score order\n" );
|
||||
for( i = 0; i < reorder->n_inputs; i++ ) {
|
||||
printf( "%2d - %8d, %8d, ",
|
||||
i, reorder->score[i], reorder->recomp_order[i] );
|
||||
vips_object_print_name( VIPS_OBJECT( reorder->input[i] ) );
|
||||
printf( "\n" );
|
||||
}
|
||||
|
||||
printf( "n_sources = %d\n", reorder->n_sources );
|
||||
printf( " n margin\n" );
|
||||
for( i = 0; i < reorder->n_sources; i++ ) {
|
||||
printf( "%2d - %8d, ",
|
||||
i, reorder->cumulative_margin[i] );
|
||||
vips_object_print_name( VIPS_OBJECT( reorder->source[i] ) );
|
||||
printf( "\n" );
|
||||
}
|
||||
|
||||
}
|
||||
#endif /*DEBUG*/
|
||||
|
||||
static void
|
||||
vips_reorder_destroy( VipsReorder *reorder )
|
||||
{
|
||||
VIPS_FREE( reorder->input );
|
||||
VIPS_FREE( reorder->score );
|
||||
VIPS_FREE( reorder->recomp_order );
|
||||
VIPS_FREE( reorder->source );
|
||||
VIPS_FREE( reorder->cumulative_margin );
|
||||
VIPS_FREE( reorder );
|
||||
}
|
||||
|
||||
static VipsReorder *
|
||||
vips_reorder_get( VipsImage *image )
|
||||
{
|
||||
VipsReorder *reorder;
|
||||
|
||||
if( (reorder = g_object_get_qdata( G_OBJECT( image ),
|
||||
vips__image_reorder_quark )) )
|
||||
return( reorder );
|
||||
|
||||
reorder = VIPS_NEW( NULL, VipsReorder );
|
||||
reorder->image = image;
|
||||
reorder->n_inputs = 0;
|
||||
reorder->input = NULL;
|
||||
reorder->score = NULL;
|
||||
reorder->recomp_order = NULL;
|
||||
reorder->n_sources = 0;
|
||||
reorder->source = NULL;
|
||||
reorder->cumulative_margin = NULL;
|
||||
|
||||
g_object_set_qdata_full( G_OBJECT( image ), vips__image_reorder_quark,
|
||||
reorder, (GDestroyNotify) vips_reorder_destroy );
|
||||
|
||||
return( reorder );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_reorder_compare_score( const void *a, const void *b, void *arg )
|
||||
{
|
||||
int i1 = *((int *) a);
|
||||
int i2 = *((int *) b);
|
||||
VipsReorder *reorder = (VipsReorder *) arg;
|
||||
|
||||
return( reorder->score[i2] - reorder->score[i1] );
|
||||
}
|
||||
|
||||
int
|
||||
vips__reorder_set_input( VipsImage *image, VipsImage **in )
|
||||
{
|
||||
VipsReorder *reorder = vips_reorder_get( image );
|
||||
|
||||
int i;
|
||||
int total;
|
||||
|
||||
/* We have to support being called more than once on the same image.
|
||||
* Two cases:
|
||||
*
|
||||
* 1. in the first call, no images were set ... we throw away
|
||||
* everything from the first call and try again. foreign can do this.
|
||||
*
|
||||
* 2. warn if the args were different and do nothing.
|
||||
*/
|
||||
if( reorder->source ) {
|
||||
if( reorder->n_inputs == 0 )
|
||||
reorder->n_sources = 0;
|
||||
else {
|
||||
for( i = 0; in[i]; i++ )
|
||||
if( i >= reorder->n_inputs ||
|
||||
in[i] != reorder->input[i] ) {
|
||||
/* Should never happen.
|
||||
*/
|
||||
g_warning( "vips__reorder_set_input: "
|
||||
"args differ\n" );
|
||||
break;
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/* Make a copy of the input array.
|
||||
*/
|
||||
for( i = 0; in[i]; i++ )
|
||||
;
|
||||
reorder->n_inputs = i;
|
||||
reorder->input = VIPS_ARRAY( NULL, reorder->n_inputs + 1, VipsImage * );
|
||||
reorder->score = VIPS_ARRAY( NULL, reorder->n_inputs, int );
|
||||
reorder->recomp_order = VIPS_ARRAY( NULL, reorder->n_inputs, int );
|
||||
if( !reorder->input )
|
||||
return( -1 );
|
||||
if( reorder->n_inputs &&
|
||||
(!reorder->score ||
|
||||
!reorder->recomp_order) )
|
||||
return( -1 );
|
||||
|
||||
for( i = 0; i < reorder->n_inputs; i++ ) {
|
||||
reorder->input[i] = in[i];
|
||||
reorder->score[i] = 0;
|
||||
reorder->recomp_order[i] = i;
|
||||
}
|
||||
reorder->input[i] = NULL;
|
||||
|
||||
/* Find the total number of source images -- this gives an upper bound
|
||||
* to the size of the unique source image array we will need.
|
||||
*/
|
||||
total = 0;
|
||||
for( i = 0; i < reorder->n_inputs; i++ )
|
||||
total += vips_reorder_get( reorder->input[i] )->n_sources;
|
||||
|
||||
/* No source images means this must itself be a source image, so it has
|
||||
* a source image of itself.
|
||||
*/
|
||||
total = VIPS_MAX( 1, total );
|
||||
|
||||
reorder->source = VIPS_ARRAY( NULL, total + 1, VipsImage * );
|
||||
reorder->cumulative_margin = VIPS_ARRAY( NULL, total, int );
|
||||
if( !reorder->source ||
|
||||
!reorder->cumulative_margin )
|
||||
return( -1 );
|
||||
|
||||
/* Copy source images over, removing duplicates. If we find a
|
||||
* duplicate, we have a reordering opportunity, and we adjust the
|
||||
* scores of the two images containing the dupe.
|
||||
*/
|
||||
for( i = 0; i < reorder->n_inputs; i++ ) {
|
||||
VipsReorder *input = vips_reorder_get( reorder->input[i] );
|
||||
|
||||
int j;
|
||||
|
||||
for( j = 0; j < input->n_sources; j++ ) {
|
||||
int k;
|
||||
|
||||
/* Search for dupe.
|
||||
*/
|
||||
for( k = 0; k < reorder->n_sources; k++ )
|
||||
if( reorder->source[k] == input->source[j] )
|
||||
break;
|
||||
|
||||
if( k < reorder->n_sources ) {
|
||||
/* Found a dupe. Does this new use of
|
||||
* input->source[j] have a larger or smaller
|
||||
* margin? Adjust the score to reflect the
|
||||
* change, note the new max.
|
||||
*/
|
||||
reorder->score[i] +=
|
||||
input->cumulative_margin[j] -
|
||||
reorder->cumulative_margin[k];
|
||||
|
||||
reorder->cumulative_margin[k] = VIPS_MAX(
|
||||
reorder->cumulative_margin[k],
|
||||
input->cumulative_margin[j] );
|
||||
|
||||
}
|
||||
else {
|
||||
/* No dupe, just add to the table.
|
||||
*/
|
||||
reorder->source[reorder->n_sources] =
|
||||
input->source[j];
|
||||
reorder->cumulative_margin[reorder->n_sources] =
|
||||
input->cumulative_margin[j];
|
||||
reorder->n_sources += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Sort recomp_order by score. qsort_r() is a GNU libc thing, don't use
|
||||
* it.
|
||||
*/
|
||||
if( reorder->n_inputs > 1 )
|
||||
g_qsort_with_data( reorder->recomp_order,
|
||||
reorder->n_inputs,
|
||||
sizeof( int ),
|
||||
vips_reorder_compare_score, reorder );
|
||||
|
||||
/* No sources ... make one, us!
|
||||
*/
|
||||
if( reorder->n_inputs == 0 ) {
|
||||
reorder->source[0] = image;
|
||||
reorder->cumulative_margin[0] = 0;
|
||||
reorder->n_sources = 1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
vips_reorder_print( reorder );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_reorder_prepare_many:
|
||||
* @image: the image that's being written
|
||||
* @regions: the set of regions to prepare
|
||||
* @r: the #VipsRect to prepare on each region
|
||||
*
|
||||
* vips_reorder_prepare_many() runs vips_region_prepare() on each region in
|
||||
* @regions, requesting the pixels in @r.
|
||||
*
|
||||
* It tries to request the regions in the order which will cause least
|
||||
* recomputation. This can give a large speedup, in some cases.
|
||||
*
|
||||
* See also: vips_region_prepare(), vips_reorder_margin_hint().
|
||||
*
|
||||
* Returns: 0 on success, or -1 on error.
|
||||
*/
|
||||
int
|
||||
vips_reorder_prepare_many( VipsImage *image, VipsRegion **regions, VipsRect *r )
|
||||
{
|
||||
VipsReorder *reorder = vips_reorder_get( image );
|
||||
|
||||
int i;
|
||||
|
||||
for( i = 0; i < reorder->n_inputs; i++ ) {
|
||||
g_assert( regions[i] );
|
||||
|
||||
if( vips_region_prepare( regions[reorder->recomp_order[i]], r ) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_reorder_margin_hint:
|
||||
* @image: the image to hint on
|
||||
* @margin: the size of the margin this operation has added
|
||||
*
|
||||
* vips_reorder_margin_hint() sets a hint that @image contains a margin, that
|
||||
* is, that each vips_region_prepare() on @image will request a slightly larger
|
||||
* region from it's inputs. A good value for @margin is (width * height) for
|
||||
* the window the operation uses.
|
||||
*
|
||||
* This information is used by vips_image_prepare_many() to attempt to reorder
|
||||
* computations to minimise recomputation.
|
||||
*
|
||||
* See also: vips_image_prepare_many().
|
||||
*/
|
||||
void
|
||||
vips_reorder_margin_hint( VipsImage *image, int margin )
|
||||
{
|
||||
VipsReorder *reorder = vips_reorder_get( image );
|
||||
|
||||
int i;
|
||||
|
||||
for( i = 0; i < reorder->n_sources; i++ )
|
||||
reorder->cumulative_margin[i] += margin;
|
||||
}
|
||||
|
||||
void
|
||||
vips__reorder_init( void )
|
||||
{
|
||||
if( !vips__image_reorder_quark )
|
||||
vips__image_reorder_quark =
|
||||
g_quark_from_static_string( "vips-image-reorder" );
|
||||
}
|
@ -120,6 +120,9 @@ vips_morph_build( VipsObject *object )
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
vips_reorder_margin_hint( morph->out,
|
||||
morph->M->Xsize * morph->M->Ysize );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
@ -391,6 +391,8 @@ vips_rank_build( VipsObject *object )
|
||||
rank->out->Xoffset = 0;
|
||||
rank->out->Yoffset = 0;
|
||||
|
||||
vips_reorder_margin_hint( rank->out, rank->width * rank->height );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
@ -540,6 +540,8 @@ vips_reduceh_build( VipsObject *object )
|
||||
in, reduceh ) )
|
||||
return( -1 );
|
||||
|
||||
vips_reorder_margin_hint( resample->out, reduceh->n_point );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
@ -813,6 +813,8 @@ vips_reducev_raw( VipsReducev *reducev, VipsImage *in )
|
||||
in, reducev ) )
|
||||
return( -1 );
|
||||
|
||||
vips_reorder_margin_hint( resample->out, reducev->n_point );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
@ -109,6 +109,30 @@ typedef struct _VipsThumbnailClass {
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE( VipsThumbnail, vips_thumbnail, VIPS_TYPE_OPERATION );
|
||||
|
||||
static void
|
||||
vips_thumbnail_dispose( GObject *gobject )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf( "vips_thumbnail_dispose: " );
|
||||
vips_object_print_name( VIPS_OBJECT( gobject ) );
|
||||
printf( "\n" );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
G_OBJECT_CLASS( vips_thumbnail_parent_class )->dispose( gobject );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_thumbnail_finalize( GObject *gobject )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf( "vips_thumbnail_finalize: " );
|
||||
vips_object_print_name( VIPS_OBJECT( gobject ) );
|
||||
printf( "\n" );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
G_OBJECT_CLASS( vips_thumbnail_parent_class )->finalize( gobject );
|
||||
}
|
||||
|
||||
/* Calculate the shrink factor, taking into account auto-rotate, the fit mode,
|
||||
* and so on.
|
||||
*/
|
||||
@ -483,6 +507,8 @@ vips_thumbnail_class_init( VipsThumbnailClass *class )
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
|
||||
|
||||
gobject_class->dispose = vips_thumbnail_dispose;
|
||||
gobject_class->finalize = vips_thumbnail_finalize;
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
|
@ -361,6 +361,10 @@ main( int argc, char **argv )
|
||||
textdomain( GETTEXT_PACKAGE );
|
||||
setlocale( LC_ALL, "" );
|
||||
|
||||
/* The operation cache is not useful for processing many files.
|
||||
vips_cache_set_max( 0 );
|
||||
*/
|
||||
|
||||
/* On Windows, argv is ascii-only .. use this to get a utf-8 version of
|
||||
* the args.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user