Merge branch '8.5'
This commit is contained in:
commit
639b0f5021
@ -12,7 +12,8 @@
|
|||||||
- rename 'disc' as 'memory' and default off
|
- rename 'disc' as 'memory' and default off
|
||||||
- add vips_find_trim(), search for non-background areas
|
- add vips_find_trim(), search for non-background areas
|
||||||
|
|
||||||
12/6/17 started 8.5.7
|
9/6/17 started 8.5.7
|
||||||
|
- better smartcrop
|
||||||
- transform cmyk->rgb automatically on write if there's an embedded profile
|
- transform cmyk->rgb automatically on write if there's an embedded profile
|
||||||
and the saver does not support cmyk
|
and the saver does not support cmyk
|
||||||
- fix DPI mixup in svgload ... we were writing images about 20% too large,
|
- fix DPI mixup in svgload ... we were writing images about 20% too large,
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
/* crop an image down to a specified size by removing boring parts
|
/* crop an image down to a specified size by removing boring parts
|
||||||
*
|
|
||||||
* Copyright: 2017, J. Cupitt
|
|
||||||
*
|
*
|
||||||
* Adapted from sharp's smartcrop feature, with kind permission.
|
* Adapted from sharp's smartcrop feature, with kind permission.
|
||||||
*
|
*
|
||||||
@ -8,6 +6,8 @@
|
|||||||
* - first version, from sharp
|
* - first version, from sharp
|
||||||
* 14/3/17
|
* 14/3/17
|
||||||
* - revised attention smartcrop
|
* - revised attention smartcrop
|
||||||
|
* 8/6/17
|
||||||
|
* - revised again
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -159,68 +159,157 @@ vips_smartcrop_entropy( VipsSmartcrop *smartcrop,
|
|||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Calculate sqrt(b1^2 + b2^2 ...)
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
pythagoras( VipsSmartcrop *smartcrop, VipsImage *in, VipsImage **out )
|
||||||
|
{
|
||||||
|
VipsImage **t = (VipsImage **)
|
||||||
|
vips_object_local_array( VIPS_OBJECT( smartcrop ),
|
||||||
|
2 * in->Bands + 1 );
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for( i = 0; i < in->Bands; i++ )
|
||||||
|
if( vips_extract_band( in, &t[i], i, NULL ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
for( i = 0; i < in->Bands; i++ )
|
||||||
|
if( vips_multiply( t[i], t[i], &t[i + in->Bands], NULL ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
if( vips_sum( &t[in->Bands], &t[2 * in->Bands], in->Bands, NULL ) ||
|
||||||
|
vips_pow_const1( t[2 * in->Bands], out, 0.5, NULL ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME
|
||||||
|
*
|
||||||
|
* Needed until 8.6, when this is in iofuncs/image.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
static VipsImage *
|
||||||
|
vips_image_new_from_image( VipsImage *image, const double *c, int n )
|
||||||
|
{
|
||||||
|
VipsObject *scope = (VipsObject *) vips_image_new();
|
||||||
|
VipsImage **t = (VipsImage **) vips_object_local_array( scope, 5 );
|
||||||
|
|
||||||
|
double *ones;
|
||||||
|
int i;
|
||||||
|
VipsImage *result;
|
||||||
|
|
||||||
|
if( !(ones = VIPS_ARRAY( scope, n, double )) ) {
|
||||||
|
g_object_unref( scope );
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
for( i = 0; i < n; i++ )
|
||||||
|
ones[i] = 1.0;
|
||||||
|
|
||||||
|
if( vips_black( &t[0], 1, 1, NULL ) ||
|
||||||
|
vips_linear( t[0], &t[1], ones, (double *) c, n, NULL ) ||
|
||||||
|
vips_cast( t[1], &t[2], image->BandFmt, NULL ) ||
|
||||||
|
vips_embed( t[2], &t[3], 0, 0, image->Xsize, image->Ysize,
|
||||||
|
"extend", VIPS_EXTEND_COPY, NULL ) ||
|
||||||
|
vips_copy( t[3], &t[4],
|
||||||
|
"interpretation", image->Type,
|
||||||
|
"xres", image->Xres,
|
||||||
|
"yres", image->Yres,
|
||||||
|
"xoffset", image->Xoffset,
|
||||||
|
"yoffset", image->Yoffset,
|
||||||
|
NULL ) ) {
|
||||||
|
g_object_unref( scope );
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
result = t[4];
|
||||||
|
g_object_ref( result );
|
||||||
|
|
||||||
|
g_object_unref( scope );
|
||||||
|
|
||||||
|
return( result );
|
||||||
|
}
|
||||||
|
|
||||||
|
static VipsImage *
|
||||||
|
vips_image_new_from_image1( VipsImage *image, double c )
|
||||||
|
{
|
||||||
|
return( vips_image_new_from_image( image, (const double *) &c, 1 ) );
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vips_smartcrop_attention( VipsSmartcrop *smartcrop,
|
vips_smartcrop_attention( VipsSmartcrop *smartcrop,
|
||||||
VipsImage *in, int *left, int *top )
|
VipsImage *in, int *left, int *top )
|
||||||
{
|
{
|
||||||
/* ab ranges for skin colours. Trained with http://humanae.tumblr.com/
|
/* From smartcrop.js.
|
||||||
*/
|
*/
|
||||||
static double ab_low[2] = { 3.0, 4.0 };
|
static double skin_vector[] = {-0.78, -0.57, -0.44};
|
||||||
static double ab_high[2] = { 22.0, 31.0 };
|
static double ones[] = {1.0, 1.0, 1.0};
|
||||||
|
|
||||||
VipsImage **t = (VipsImage **)
|
VipsImage **t = (VipsImage **)
|
||||||
vips_object_local_array( VIPS_OBJECT( smartcrop ), 24 );
|
vips_object_local_array( VIPS_OBJECT( smartcrop ), 24 );
|
||||||
|
|
||||||
double hshrink;
|
double hscale;
|
||||||
double vshrink;
|
double vscale;
|
||||||
double sigma;
|
double sigma;
|
||||||
double max;
|
double max;
|
||||||
int x_pos;
|
int x_pos;
|
||||||
int y_pos;
|
int y_pos;
|
||||||
|
|
||||||
|
/* Simple edge detect.
|
||||||
|
*/
|
||||||
if( !(t[21] = vips_image_new_matrixv( 3, 3,
|
if( !(t[21] = vips_image_new_matrixv( 3, 3,
|
||||||
-1.0, 0.0, 1.0, -2.0, 0.0, 2.0, -1.0, 0.0, 1.0 )) )
|
0.0, -1.0, 0.0,
|
||||||
return( -1 );
|
-1.0, 4.0, -1.0,
|
||||||
if( vips_rot( t[21], &t[22], VIPS_ANGLE_D90, NULL ) )
|
0.0, -1.0, 0.0 )) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
/* Convert to LAB and just use the first three bands.
|
/* Convert to XYZ and just use the first three bands.
|
||||||
*/
|
*/
|
||||||
if( vips_colourspace( in, &t[0], VIPS_INTERPRETATION_LAB, NULL ) ||
|
if( vips_colourspace( in, &t[0], VIPS_INTERPRETATION_XYZ, NULL ) ||
|
||||||
vips_extract_band( t[0], &t[1], 0, "n", 3, NULL ) )
|
vips_extract_band( t[0], &t[1], 0, "n", 3, NULL ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
/* Sobel edge-detect on L.
|
/* Edge detect on Y.
|
||||||
*/
|
*/
|
||||||
if( vips_extract_band( t[1], &t[2], 0, NULL ) ||
|
if( vips_extract_band( t[1], &t[2], 1, NULL ) ||
|
||||||
vips_conv( t[2], &t[3], t[21],
|
vips_conv( t[2], &t[3], t[21],
|
||||||
"precision", VIPS_PRECISION_INTEGER,
|
"precision", VIPS_PRECISION_INTEGER,
|
||||||
NULL ) ||
|
NULL ) ||
|
||||||
vips_conv( t[2], &t[4], t[22],
|
vips_linear1( t[3], &t[4], 5.0, 0.0, NULL ) ||
|
||||||
"precision", VIPS_PRECISION_INTEGER,
|
vips_abs( t[4], &t[14], NULL ) )
|
||||||
NULL ) ||
|
|
||||||
vips_abs( t[3], &t[5], NULL ) ||
|
|
||||||
vips_abs( t[4], &t[6], NULL ) ||
|
|
||||||
vips_add( t[5], t[6], &t[7], NULL ) )
|
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
/* Look for skin colours, plus L > 15.
|
/* Look for skin colours. Taken from smartcrop.js.
|
||||||
*/
|
*/
|
||||||
if( vips_extract_band( t[1], &t[8], 1, "n", 2, NULL ) ||
|
if(
|
||||||
vips_moreeq_const( t[8], &t[9], ab_low, 2, NULL ) ||
|
/* Normalise to magnitude of colour in XYZ.
|
||||||
vips_lesseq_const( t[8], &t[10], ab_high, 2, NULL ) ||
|
*/
|
||||||
vips_andimage( t[9], t[10], &t[11], NULL ) ||
|
pythagoras( smartcrop, t[1], &t[5] ) ||
|
||||||
vips_bandand( t[11], &t[12], NULL ) ||
|
vips_divide( t[1], t[5], &t[6], NULL ) ||
|
||||||
vips_moreeq_const1( t[2], &t[18], 15.0, NULL ) ||
|
|
||||||
vips_andimage( t[12], t[18], &t[19], NULL ) )
|
/* Distance from skin point.
|
||||||
|
*/
|
||||||
|
vips_linear( t[6], &t[7], ones, skin_vector, 3, NULL ) ||
|
||||||
|
pythagoras( smartcrop, t[7], &t[8] ) ||
|
||||||
|
|
||||||
|
/* Rescale to 100 - 0 score.
|
||||||
|
*/
|
||||||
|
vips_linear1( t[8], &t[9], -100.0, 100.0, NULL ) ||
|
||||||
|
|
||||||
|
/* Ignore dark areas.
|
||||||
|
*/
|
||||||
|
vips_more_const1( t[2], &t[10], 5.0, NULL ) ||
|
||||||
|
!(t[11] = vips_image_new_from_image1( t[10], 0.0 )) ||
|
||||||
|
vips_ifthenelse( t[10], t[9], t[11], &t[15], NULL ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
/* Look for saturated areas.
|
/* Look for saturated areas.
|
||||||
*/
|
*/
|
||||||
if( vips_colourspace( t[1], &t[13],
|
if( vips_colourspace( t[1], &t[12],
|
||||||
VIPS_INTERPRETATION_LCH, NULL ) ||
|
VIPS_INTERPRETATION_LCH, NULL ) ||
|
||||||
vips_extract_band( t[13], &t[14], 1, NULL ) ||
|
vips_extract_band( t[12], &t[13], 1, NULL ) ||
|
||||||
vips_more_const1( t[14], &t[15], 60.0, NULL ) )
|
vips_ifthenelse( t[10], t[13], t[11], &t[16], NULL ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
/* Sum, shrink, blur and find maxpos.
|
/* Sum, shrink, blur and find maxpos.
|
||||||
@ -230,24 +319,26 @@ vips_smartcrop_attention( VipsSmartcrop *smartcrop,
|
|||||||
* area: how large an area we want to consider for the scoring
|
* area: how large an area we want to consider for the scoring
|
||||||
* function.
|
* function.
|
||||||
*/
|
*/
|
||||||
hshrink = in->Xsize / 32.0;
|
hscale = 32.0 / in->Xsize;
|
||||||
vshrink = in->Ysize / 32.0;
|
vscale = 32.0 / in->Ysize;
|
||||||
sigma = sqrt( pow( smartcrop->width / hshrink, 2 ) +
|
sigma = sqrt( pow( smartcrop->width * hscale, 2 ) +
|
||||||
pow( smartcrop->height / vshrink, 2 ) ) / 6;
|
pow( smartcrop->height * vscale, 2 ) ) / 10;
|
||||||
if( vips_add( t[7], t[19], &t[16], NULL ) ||
|
if( vips_sum( &t[14], &t[17], 3, NULL ) ||
|
||||||
vips_add( t[16], t[15], &t[17], NULL ) ||
|
vips_resize( t[17], &t[18], hscale,
|
||||||
vips_shrink( t[17], &t[20], hshrink, vshrink, NULL ) ||
|
"vscale", vscale,
|
||||||
vips_gaussblur( t[20], &t[23], sigma, NULL ) ||
|
"kernel", VIPS_KERNEL_LINEAR,
|
||||||
vips_max( t[23], &max, "x", &x_pos, "y", &y_pos, NULL ) )
|
NULL ) ||
|
||||||
|
vips_gaussblur( t[18], &t[19], sigma, NULL ) ||
|
||||||
|
vips_max( t[19], &max, "x", &x_pos, "y", &y_pos, NULL ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
/* Centre the crop over the max.
|
/* Centre the crop over the max.
|
||||||
*/
|
*/
|
||||||
*left = VIPS_CLIP( 0,
|
*left = VIPS_CLIP( 0,
|
||||||
hshrink * x_pos - smartcrop->width / 2,
|
x_pos / hscale - smartcrop->width / 2,
|
||||||
in->Xsize - smartcrop->width );
|
in->Xsize - smartcrop->width );
|
||||||
*top = VIPS_CLIP( 0,
|
*top = VIPS_CLIP( 0,
|
||||||
vshrink * y_pos - smartcrop->height / 2,
|
y_pos / vscale - smartcrop->height / 2,
|
||||||
in->Ysize - smartcrop->height );
|
in->Ysize - smartcrop->height );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
|
6
libvips/fuzz/Makefile.am
Normal file
6
libvips/fuzz/Makefile.am
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
noinst_LTLIBRARIES = libfuzz.la
|
||||||
|
|
||||||
|
libfuzz_la_SOURCES = \
|
||||||
|
fuzz_new_from_buffer.c
|
||||||
|
|
||||||
|
AM_CPPFLAGS = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@
|
64
libvips/fuzz/fuzz_new_from_buffer.c
Normal file
64
libvips/fuzz/fuzz_new_from_buffer.c
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/* fuzz targets for libfuzzer
|
||||||
|
*
|
||||||
|
* 28/7/17
|
||||||
|
* - first attempt
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
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 VIPS_DEBUG
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif /*HAVE_CONFIG_H*/
|
||||||
|
#include <vips/intl.h>
|
||||||
|
|
||||||
|
#include <vips/vips.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
vips__fuzztarget_new_from_buffer( const guint8 *data, size_t size )
|
||||||
|
{
|
||||||
|
VipsImage *image;
|
||||||
|
double d;
|
||||||
|
|
||||||
|
/* Have one for each format as well.
|
||||||
|
*/
|
||||||
|
if( !(image = vips_image_new_from_buffer( data, size, "", NULL )) )
|
||||||
|
/* libfuzzer does not allow error return.
|
||||||
|
*/
|
||||||
|
return( 0 );
|
||||||
|
|
||||||
|
if( vips_avg( image, &d, NULL ) )
|
||||||
|
return( 0 );
|
||||||
|
|
||||||
|
g_object_unref( image );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
@ -187,6 +187,10 @@ int vips__init( const char *argv0 );
|
|||||||
size_t vips__get_sizeof_vipsobject( void );
|
size_t vips__get_sizeof_vipsobject( void );
|
||||||
int vips_region_prepare_many( struct _VipsRegion **reg, VipsRect *r );
|
int vips_region_prepare_many( struct _VipsRegion **reg, VipsRect *r );
|
||||||
|
|
||||||
|
/* Handy for debugging.
|
||||||
|
*/
|
||||||
|
int vips__view_image( struct _VipsImage *image );
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /*__cplusplus*/
|
#endif /*__cplusplus*/
|
||||||
|
@ -3629,3 +3629,21 @@ vips_band_format_iscomplex( VipsBandFormat format )
|
|||||||
return( FALSE );
|
return( FALSE );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handy for debugging: view an image in nip2.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
vips__view_image( VipsImage *image )
|
||||||
|
{
|
||||||
|
VipsArrayImage *array;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
array = vips_array_image_new( &image, 1 );
|
||||||
|
result = vips_system( "nip2 %s",
|
||||||
|
"in", array,
|
||||||
|
"in-format", "%s.v",
|
||||||
|
NULL );
|
||||||
|
vips_area_unref( VIPS_AREA( array ) );
|
||||||
|
|
||||||
|
return( result );
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user