Merge pull request #1264 from omira-sch/add-oss-fuzz
improve fuzz targets and oss-fuzz integration
This commit is contained in:
commit
a6fbf1af36
28
.travis.yml
28
.travis.yml
@ -10,9 +10,10 @@ before_script:
|
|||||||
--with-jpeg-libraries=$JPEG/lib
|
--with-jpeg-libraries=$JPEG/lib
|
||||||
- make -j$JOBS -s
|
- make -j$JOBS -s
|
||||||
script:
|
script:
|
||||||
- make -Ctest -j$JOBS -s V=0 VERBOSE=1 check
|
- make -j$JOBS -s -k V=0 VERBOSE=1 check
|
||||||
- LD_LIBRARY_PATH=$PWD/libvips/.libs
|
- LD_LIBRARY_PATH=$PWD/libvips/.libs
|
||||||
DYLD_LIBRARY_PATH=$PWD/libvips/.libs
|
DYLD_LIBRARY_PATH=$PWD/libvips/.libs
|
||||||
|
LD_PRELOAD=$ASAN_DSO
|
||||||
$PYTHON -m pytest -v test/test-suite
|
$PYTHON -m pytest -v test/test-suite
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
@ -23,6 +24,7 @@ matrix:
|
|||||||
- os: linux
|
- os: linux
|
||||||
sudo: required
|
sudo: required
|
||||||
dist: xenial
|
dist: xenial
|
||||||
|
compiler: gcc
|
||||||
env:
|
env:
|
||||||
- PYTHON=python2
|
- PYTHON=python2
|
||||||
- PYVIPS_VERSION=master
|
- PYVIPS_VERSION=master
|
||||||
@ -30,6 +32,29 @@ matrix:
|
|||||||
- JOBS=`nproc`
|
- JOBS=`nproc`
|
||||||
cache: ccache
|
cache: ccache
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
sudo: required
|
||||||
|
dist: xenial
|
||||||
|
compiler: clang
|
||||||
|
env:
|
||||||
|
- PYTHON=python2
|
||||||
|
- PYVIPS_VERSION=master
|
||||||
|
- JPEG=/usr
|
||||||
|
- JOBS=`nproc`
|
||||||
|
- CFLAGS="-fsanitize=address -fno-omit-frame-pointer -fopenmp"
|
||||||
|
- LDFLAGS="-fsanitize=address -dynamic-asan -fopenmp=libiomp5"
|
||||||
|
- ASAN_DSO=/usr/local/clang-7.0.0/lib/clang/7.0.0/lib/linux/libclang_rt.asan-x86_64.so
|
||||||
|
- LSAN_OPTIONS="suppressions=$TRAVIS_BUILD_DIR/lsan.supp"
|
||||||
|
- FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1
|
||||||
|
install:
|
||||||
|
# add support for WebP
|
||||||
|
- wget http://archive.ubuntu.com/ubuntu/pool/main/libw/libwebp/libwebp-dev_0.6.1-2_amd64.deb
|
||||||
|
- wget http://archive.ubuntu.com/ubuntu/pool/main/libw/libwebp/libwebpdemux2_0.6.1-2_amd64.deb
|
||||||
|
- wget http://archive.ubuntu.com/ubuntu/pool/main/libw/libwebp/libwebpmux3_0.6.1-2_amd64.deb
|
||||||
|
- wget http://archive.ubuntu.com/ubuntu/pool/main/libw/libwebp/libwebp6_0.6.1-2_amd64.deb
|
||||||
|
- sudo dpkg -i *.deb
|
||||||
|
cache: ccache
|
||||||
|
|
||||||
- os: osx
|
- os: osx
|
||||||
osx_image: xcode10.1
|
osx_image: xcode10.1
|
||||||
env:
|
env:
|
||||||
@ -79,6 +104,7 @@ addons:
|
|||||||
- libgsf-1-dev
|
- libgsf-1-dev
|
||||||
- libopenslide-dev
|
- libopenslide-dev
|
||||||
- libffi-dev
|
- libffi-dev
|
||||||
|
- libiomp-dev
|
||||||
homebrew:
|
homebrew:
|
||||||
packages:
|
packages:
|
||||||
- ccache
|
- ccache
|
||||||
|
@ -5,7 +5,8 @@ SUBDIRS = \
|
|||||||
po \
|
po \
|
||||||
man \
|
man \
|
||||||
doc \
|
doc \
|
||||||
test
|
test \
|
||||||
|
fuzz
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
m4 \
|
m4 \
|
||||||
@ -14,6 +15,7 @@ EXTRA_DIST = \
|
|||||||
vips.pc.in \
|
vips.pc.in \
|
||||||
vips-cpp.pc.in \
|
vips-cpp.pc.in \
|
||||||
libvips.supp \
|
libvips.supp \
|
||||||
|
lsan.supp \
|
||||||
depcomp \
|
depcomp \
|
||||||
README.md
|
README.md
|
||||||
|
|
||||||
|
@ -1388,6 +1388,13 @@ if test x"$with_libexif" != x"no"; then
|
|||||||
CPPFLAGS="$save_CPPFLAGS"
|
CPPFLAGS="$save_CPPFLAGS"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# fuzzing
|
||||||
|
AC_ARG_VAR([LIB_FUZZING_ENGINE],
|
||||||
|
[fuzzing library, e.g. /path/to/libFuzzer.a])
|
||||||
|
if test x"$LIB_FUZZING_ENGINE" = x; then
|
||||||
|
LIB_FUZZING_ENGINE="libstandaloneengine.a"
|
||||||
|
fi
|
||||||
|
|
||||||
# Gather all up for VIPS_CFLAGS, VIPS_INCLUDES, VIPS_LIBS
|
# Gather all up for VIPS_CFLAGS, VIPS_INCLUDES, VIPS_LIBS
|
||||||
# sort includes to get longer, more specific dirs first
|
# sort includes to get longer, more specific dirs first
|
||||||
# helps, for example, selecting graphicsmagick over imagemagick
|
# helps, for example, selecting graphicsmagick over imagemagick
|
||||||
@ -1452,6 +1459,7 @@ AC_OUTPUT([
|
|||||||
doc/Makefile
|
doc/Makefile
|
||||||
doc/libvips-docs.xml
|
doc/libvips-docs.xml
|
||||||
po/Makefile.in
|
po/Makefile.in
|
||||||
|
fuzz/Makefile
|
||||||
])
|
])
|
||||||
|
|
||||||
AC_MSG_RESULT([dnl
|
AC_MSG_RESULT([dnl
|
||||||
|
25
fuzz/Makefile.am
Normal file
25
fuzz/Makefile.am
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
TESTS = \
|
||||||
|
test_fuzz.sh
|
||||||
|
|
||||||
|
FUZZPROGS = \
|
||||||
|
jpegsave_buffer_fuzzer \
|
||||||
|
pngsave_buffer_fuzzer \
|
||||||
|
webpsave_buffer_fuzzer \
|
||||||
|
sharpen_fuzzer \
|
||||||
|
thumbnail_fuzzer
|
||||||
|
|
||||||
|
AM_DEFAULT_SOURCE_EXT = .cc
|
||||||
|
|
||||||
|
FUZZLIBS = libstandaloneengine.a
|
||||||
|
|
||||||
|
# Include debug symbols by default as recommended by libfuzzer
|
||||||
|
AM_CXXFLAGS = -g -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@
|
||||||
|
AM_LDFLAGS = @LDFLAGS@
|
||||||
|
LDADD = ${top_builddir}/libvips/libvips.la @VIPS_LIBS@ @LIB_FUZZING_ENGINE@
|
||||||
|
|
||||||
|
libstandaloneengine_a_SOURCES = StandaloneFuzzTargetMain.c
|
||||||
|
|
||||||
|
check_PROGRAMS = $(FUZZPROGS)
|
||||||
|
noinst_LIBRARIES = $(FUZZLIBS)
|
||||||
|
|
||||||
|
EXTRA_DIST = $(TESTS)
|
46
fuzz/StandaloneFuzzTargetMain.c
Normal file
46
fuzz/StandaloneFuzzTargetMain.c
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*===- StandaloneFuzzTargetMain.c - standalone main() for fuzz targets. ---===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// This main() function can be linked to a fuzz target (i.e. a library
|
||||||
|
// that exports LLVMFuzzerTestOneInput() and possibly LLVMFuzzerInitialize())
|
||||||
|
// instead of libFuzzer. This main() function will not perform any fuzzing
|
||||||
|
// but will simply feed all input files one by one to the fuzz target.
|
||||||
|
//
|
||||||
|
// Use this file to provide reproducers for bugs when linking against libFuzzer
|
||||||
|
// or other fuzzing engine is undesirable.
|
||||||
|
//===----------------------------------------------------------------------===*/
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size);
|
||||||
|
extern int LLVMFuzzerInitialize(int *argc, char ***argv);
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
const char *progname;
|
||||||
|
if ((progname = strrchr(argv[0], '/')))
|
||||||
|
progname++;
|
||||||
|
else
|
||||||
|
progname = argv[0];
|
||||||
|
fprintf(stderr, "%s: running %d inputs\n", progname, argc - 1);
|
||||||
|
LLVMFuzzerInitialize(&argc, &argv);
|
||||||
|
for (int i = 1; i < argc; i++) {
|
||||||
|
fprintf(stderr, "Running: %s\n", argv[i]);
|
||||||
|
FILE *f = fopen(argv[i], "r+");
|
||||||
|
assert(f);
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
long len = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
unsigned char *buf = (unsigned char*)malloc(len);
|
||||||
|
size_t n_read = fread(buf, 1, len, f);
|
||||||
|
fclose(f);
|
||||||
|
assert(n_read == len);
|
||||||
|
LLVMFuzzerTestOneInput(buf, len);
|
||||||
|
free(buf);
|
||||||
|
fprintf(stderr, "Done: %s: (%zd bytes)\n", argv[i], n_read);
|
||||||
|
}
|
||||||
|
}
|
30
fuzz/jpegsave_buffer_fuzzer.cc
Normal file
30
fuzz/jpegsave_buffer_fuzzer.cc
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include <vips/vips.h>
|
||||||
|
|
||||||
|
extern "C" int
|
||||||
|
LLVMFuzzerInitialize( int *argc, char ***argv )
|
||||||
|
{
|
||||||
|
vips_concurrency_set( 1 );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int
|
||||||
|
LLVMFuzzerTestOneInput( const guint8 *data, size_t size )
|
||||||
|
{
|
||||||
|
VipsImage *image;
|
||||||
|
size_t len;
|
||||||
|
void *buf;
|
||||||
|
|
||||||
|
if( !(image = vips_image_new_from_buffer( data, size, "", NULL )) ) {
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( vips_jpegsave_buffer( image, &buf, &len, NULL ) ) {
|
||||||
|
g_object_unref( image );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free( buf );
|
||||||
|
g_object_unref( image );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
0
fuzz/jpegsave_buffer_fuzzer_corpus/.keep
Normal file
0
fuzz/jpegsave_buffer_fuzzer_corpus/.keep
Normal file
30
fuzz/pngsave_buffer_fuzzer.cc
Normal file
30
fuzz/pngsave_buffer_fuzzer.cc
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include <vips/vips.h>
|
||||||
|
|
||||||
|
extern "C" int
|
||||||
|
LLVMFuzzerInitialize( int *argc, char ***argv )
|
||||||
|
{
|
||||||
|
vips_concurrency_set( 1 );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int
|
||||||
|
LLVMFuzzerTestOneInput( const guint8 *data, size_t size )
|
||||||
|
{
|
||||||
|
VipsImage *image;
|
||||||
|
void *buf;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if( !(image = vips_image_new_from_buffer( data, size, "", NULL )) ) {
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( vips_pngsave_buffer( image, &buf, &len, NULL ) ) {
|
||||||
|
g_object_unref( image );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free( buf );
|
||||||
|
g_object_unref( image );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
0
fuzz/pngsave_buffer_fuzzer_corpus/.keep
Normal file
0
fuzz/pngsave_buffer_fuzzer_corpus/.keep
Normal file
31
fuzz/sharpen_fuzzer.cc
Normal file
31
fuzz/sharpen_fuzzer.cc
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include <vips/vips.h>
|
||||||
|
|
||||||
|
extern "C" int
|
||||||
|
LLVMFuzzerInitialize( int *argc, char ***argv )
|
||||||
|
{
|
||||||
|
vips_concurrency_set( 1 );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int
|
||||||
|
LLVMFuzzerTestOneInput( const guint8 *data, size_t size )
|
||||||
|
{
|
||||||
|
VipsImage *in, *out;
|
||||||
|
double d;
|
||||||
|
|
||||||
|
if( !(in = vips_image_new_from_buffer( data, size, "", NULL )) ) {
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( vips_sharpen( in, &out, NULL ) ) {
|
||||||
|
g_object_unref( in );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
vips_avg( out, &d, NULL );
|
||||||
|
|
||||||
|
g_object_unref( out );
|
||||||
|
g_object_unref( in );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
0
fuzz/sharpen_fuzzer_corpus/.keep
Normal file
0
fuzz/sharpen_fuzzer_corpus/.keep
Normal file
20
fuzz/test_fuzz.sh
Executable file
20
fuzz/test_fuzz.sh
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#set -x
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Glib is build without -fno-omit-frame-pointer. We need
|
||||||
|
# to disable the fast unwinder to get full stacktraces.
|
||||||
|
export ASAN_OPTIONS="fast_unwind_on_malloc=0:allocator_may_return_null=1"
|
||||||
|
|
||||||
|
# Hide all warning messages from vips.
|
||||||
|
export VIPS_WARNING=0
|
||||||
|
|
||||||
|
ret=0
|
||||||
|
|
||||||
|
for fuzzer in *_fuzzer; do
|
||||||
|
find "${fuzzer}_corpus" -type f -not -empty -print0 \
|
||||||
|
| xargs -0 -n1 "./$fuzzer" || ret=1
|
||||||
|
done
|
||||||
|
|
||||||
|
exit $ret
|
42
fuzz/thumbnail_fuzzer.cc
Normal file
42
fuzz/thumbnail_fuzzer.cc
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#include <vips/vips.h>
|
||||||
|
|
||||||
|
extern "C" int
|
||||||
|
LLVMFuzzerInitialize( int *argc, char ***argv )
|
||||||
|
{
|
||||||
|
vips_concurrency_set( 1 );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int
|
||||||
|
LLVMFuzzerTestOneInput( const guint8 *data, size_t size )
|
||||||
|
{
|
||||||
|
VipsImage *in, *out;
|
||||||
|
size_t width, height;
|
||||||
|
double d;
|
||||||
|
|
||||||
|
if( !(in = vips_image_new_from_buffer( data, size, "", NULL )) ) {
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
width = in->Xsize;
|
||||||
|
height = in->Ysize;
|
||||||
|
|
||||||
|
/* Skip big images. It is likely to timeout.
|
||||||
|
*/
|
||||||
|
if ( width * height > 256 * 256 ) {
|
||||||
|
g_object_unref( in );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( vips_thumbnail_image( in, &out, 42, NULL ) ) {
|
||||||
|
g_object_unref( in );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
vips_avg( out, &d, NULL );
|
||||||
|
|
||||||
|
g_object_unref( out );
|
||||||
|
g_object_unref( in );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
0
fuzz/thumbnail_fuzzer_corpus/.keep
Normal file
0
fuzz/thumbnail_fuzzer_corpus/.keep
Normal file
30
fuzz/webpsave_buffer_fuzzer.cc
Normal file
30
fuzz/webpsave_buffer_fuzzer.cc
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include <vips/vips.h>
|
||||||
|
|
||||||
|
extern "C" int
|
||||||
|
LLVMFuzzerInitialize( int *argc, char ***argv )
|
||||||
|
{
|
||||||
|
vips_concurrency_set( 1 );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int
|
||||||
|
LLVMFuzzerTestOneInput( const guint8 *data, size_t size )
|
||||||
|
{
|
||||||
|
VipsImage *image;
|
||||||
|
void *buf;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if( !(image = vips_image_new_from_buffer( data, size, "", NULL )) ) {
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( vips_webpsave_buffer( image, &buf, &len, NULL ) ) {
|
||||||
|
g_object_unref( image );
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free( buf );
|
||||||
|
g_object_unref( image );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
0
fuzz/webpsave_buffer_fuzzer_corpus/.keep
Normal file
0
fuzz/webpsave_buffer_fuzzer_corpus/.keep
Normal file
@ -231,6 +231,13 @@ read_new( VipsImage *out, gboolean fail )
|
|||||||
PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON );
|
PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON );
|
||||||
#endif /*PNG_SKIP_sRGB_CHECK_PROFILE*/
|
#endif /*PNG_SKIP_sRGB_CHECK_PROFILE*/
|
||||||
|
|
||||||
|
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||||
|
/* Disable CRC checking in fuzzing mode.
|
||||||
|
*/
|
||||||
|
png_set_crc_action( read->pPng,
|
||||||
|
PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE );
|
||||||
|
#endif /*FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION*/
|
||||||
|
|
||||||
/* Catch PNG errors from png_create_info_struct().
|
/* Catch PNG errors from png_create_info_struct().
|
||||||
*/
|
*/
|
||||||
if( setjmp( png_jmpbuf( read->pPng ) ) )
|
if( setjmp( png_jmpbuf( read->pPng ) ) )
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
noinst_LTLIBRARIES = libfuzz.la
|
|
||||||
|
|
||||||
libfuzz_la_SOURCES = \
|
|
||||||
fuzz_new_from_buffer.c
|
|
||||||
|
|
||||||
AM_CPPFLAGS = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@
|
|
@ -1,64 +0,0 @@
|
|||||||
/* 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 );
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user