Merge branch 'master' of github.com:libvips/libvips

This commit is contained in:
John Cupitt 2021-02-14 14:00:28 +00:00
commit 9c172674bf
23 changed files with 737 additions and 359 deletions

144
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,144 @@
name: CI
on: [ push, pull_request, workflow_dispatch ]
jobs:
CI:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
continue-on-error: ${{ contains(matrix.os, 'macos') }}
strategy:
fail-fast: false
matrix:
name: [ "Linux x64 (Ubuntu 20.04) - GCC 10" ]
os: [ ubuntu-20.04 ]
sanitize: [ false ]
build:
- { cc: gcc, cxx: g++, linker: ld }
include:
- name: "Linux x64 (Ubuntu 20.04) - Clang 10 with ASan and UBSan"
os: ubuntu-20.04
sanitize: true
build: { cc: clang-10, cxx: clang++-10, linker: ld.lld-10 }
- name: "macOS (10.15) - Xcode 12.3"
os: macos-10.15
sanitize: false
build: { cc: clang, cxx: clang++, linker: ld.lld }
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Update apt
if: contains(matrix.os, 'ubuntu')
env:
DEBIAN_FRONTEND: noninteractive
run: sudo -E apt-get update -qq -o Acquire::Retries=3
- name: Add libheif PPA
if: contains(matrix.os, 'ubuntu')
run: |
sudo add-apt-repository ppa:strukturag/libde265
sudo add-apt-repository ppa:strukturag/libheif
- name: Install Ubuntu dependencies
if: contains(matrix.os, 'ubuntu')
env:
DEBIAN_FRONTEND: noninteractive
run:
sudo -E apt-get install --fix-missing -qq -o Acquire::Retries=3
gtk-doc-tools gobject-introspection
python3-pip python3-setuptools python3-wheel
libfftw3-dev libexif-dev libjpeg-turbo8-dev
libpng-dev libwebp-dev libtiff5-dev
libheif-dev libexpat1-dev libcfitsio-dev
libmatio-dev libnifti-dev liborc-0.4-dev
liblcms2-dev libpoppler-glib-dev librsvg2-dev
libgif-dev libopenexr-dev libpango1.0-dev
libgsf-1-dev libopenslide-dev libffi-dev
- name: Install macOS dependencies
if: contains(matrix.os, 'macos')
run:
brew install
autoconf automake libtool
gtk-doc gobject-introspection
cfitsio fftw giflib
glib libexif libgsf
libheif libjpeg-turbo libmatio
librsvg libspng libtiff
little-cms2 openexr openslide
orc pango poppler webp
- name: Install Clang 10
env:
DEBIAN_FRONTEND: noninteractive
if: contains(matrix.os, 'ubuntu') && matrix.build.cc == 'clang-10'
run:
sudo -E apt-get install --fix-missing -qq -o Acquire::Retries=3
clang-10 libomp-10-dev lld-10 llvm-10
- name: Prepare build environment
run: |
echo "CC=${{ matrix.build.cc }}" >> $GITHUB_ENV
echo "CXX=${{ matrix.build.cxx }}" >> $GITHUB_ENV
echo "LD=${{ matrix.build.linker }}" >> $GITHUB_ENV
echo "CPPFLAGS=-Wall" >> $GITHUB_ENV
- name: Prepare Ubuntu environment
if: contains(matrix.os, 'ubuntu')
run: echo "JOBS=$(nproc)" >> $GITHUB_ENV
- name: Prepare macOS environment
if: contains(matrix.os, 'macos')
run: |
echo "JOBS=$(sysctl -n hw.logicalcpu)" >> $GITHUB_ENV
echo "PKG_CONFIG_PATH=/usr/local/opt/jpeg-turbo/lib/pkgconfig:/usr/local/opt/libxml2/lib/pkgconfig" >> $GITHUB_ENV
- name: Prepare sanitizers
if: matrix.sanitize
env:
LLVM_PREFIX: /usr/lib/llvm-10
run: |
ASAN_DSO=`$CC -print-file-name=libclang_rt.asan-x86_64.so`
echo "LDSHARED=$CC -shared" >> $GITHUB_ENV
echo "CPPFLAGS=-g -fsanitize=address,undefined -fno-omit-frame-pointer -fopenmp -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION" >> $GITHUB_ENV
echo "LDFLAGS=-g -fsanitize=address,undefined -shared-libasan -fopenmp=libomp" >> $GITHUB_ENV
echo "ASAN_DSO=$ASAN_DSO" >> $GITHUB_ENV
echo "ASAN_OPTIONS=suppressions=${{ github.workspace }}/suppressions/asan.supp" >> $GITHUB_ENV
echo "LSAN_OPTIONS=suppressions=${{ github.workspace }}/suppressions/lsan.supp" >> $GITHUB_ENV
echo "UBSAN_OPTIONS=suppressions=${{ github.workspace }}/suppressions/ubsan.supp:print_stacktrace=1" >> $GITHUB_ENV
echo "LD_LIBRARY_PATH=$LLVM_PREFIX/lib:`dirname $ASAN_DSO`" >> $GITHUB_ENV
echo "$LLVM_PREFIX/bin" >> $GITHUB_PATH
# workaround for https://github.com/google/sanitizers/issues/89
# otherwise libIlmImf-2_3.so ends up as <unknown module>
echo "DLCLOSE_PRELOAD=${{ github.workspace }}/dlclose.so" >> $GITHUB_ENV
echo -e '#include <stdio.h>\nint dlclose(void*handle){return 0;}' | $CC -shared -xc -odlclose.so -
- name: Configure libvips
run:
./autogen.sh
--disable-dependency-tracking
--disable-deprecated || (cat config.log && exit 1)
- name: Build libvips
run: make V=0 -j$JOBS
- name: Check libvips
run: make V=0 check
- name: Install libvips
run: sudo make V=0 install
- name: Rebuild the shared library cache
if: contains(matrix.os, 'ubuntu')
run: sudo ldconfig
- name: Install pyvips
run: pip3 install pyvips[test]
- name: Run test suite
env:
VIPS_LEAK: 1
LD_PRELOAD: ${{ env.ASAN_DSO }} ${{ env.DLCLOSE_PRELOAD }}
run: python3 -m pytest -sv --log-cli-level=WARNING test/test-suite

View File

@ -1,84 +0,0 @@
name: Test
# to-do:
# - add a macos test with brew etc.
# - build with clang/asan/etc. and run the fuzz tests
on:
- push
- pull_request
- workflow_dispatch # manually triggered workflow
jobs:
build:
runs-on: ubuntu-20.04
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Update apt
env:
DEBIAN_FRONTEND: noninteractive
run:
sudo apt-get update -qq -o Acquire::Retries=3
- name: Add libheif PPA
run: |
sudo add-apt-repository ppa:strukturag/libde265
sudo add-apt-repository ppa:strukturag/libheif
- name: Install platform dependencies
env:
DEBIAN_FRONTEND: noninteractive
run:
sudo apt-get install --fix-missing -qq -o Acquire::Retries=3
gtk-doc-tools
gobject-introspection
python3-pip
python3-setuptools
python3-wheel
libfftw3-dev
libexif-dev
libjpeg-turbo8-dev
libpng-dev
libwebp-dev
libtiff5-dev
libheif-dev
libexpat1-dev
libcfitsio-dev
libgsl-dev
libmatio-dev
libnifti-dev
liborc-0.4-dev
liblcms2-dev
libpoppler-glib-dev
librsvg2-dev
libgif-dev
libopenexr-dev
libpango1.0-dev
libgsf-1-dev
libopenslide-dev
libffi-dev
- name: Configure libvips
run: CFLAGS=-Wall CXXFLAGS=-Wall ./autogen.sh
--disable-dependency-tracking
--disable-deprecated
- name: Build libvips
run: make V=0 -j$(nproc)
- name: Check libvips
run: make V=0 check
- name: Install libvips
run: |
sudo make V=0 install
sudo ldconfig
- name: Install pyvips
run: pip3 install pyvips pytest
- name: Run test suite
run: python3 -m pytest

View File

@ -1,163 +0,0 @@
language: cpp
env:
global:
- PYTHON=python3
- PYVIPS_VERSION=master
addons:
apt:
update: true
sources: &common_sources
# add support for AVIF files
- sourceline: 'ppa:strukturag/libheif'
- sourceline: 'ppa:strukturag/libde265'
packages: &common_packages
- gtk-doc-tools
- gobject-introspection
- python3-pip
- python3-setuptools
- python3-wheel
- libfftw3-dev
- libexif-dev
- libjpeg-turbo8-dev
- libpng-dev
- libwebp-dev
- libtiff5-dev
- libheif-dev
- libexpat1-dev
- libcfitsio-dev
- libgsl-dev
- libmatio-dev
- libnifti-dev
- liborc-0.4-dev
- liblcms2-dev
- libpoppler-glib-dev
- librsvg2-dev
- libgif-dev
- libopenexr-dev
- libpango1.0-dev
- libgsf-1-dev
- libopenslide-dev
- libffi-dev
homebrew:
update: true
packages:
- ccache
- cfitsio
- fftw
- giflib
- glib
- gobject-introspection
- gtk-doc
- libexif
- libgsf
- libheif
- libjpeg-turbo
- libmatio
- librsvg
- libspng
- libtiff
- little-cms2
- openexr
- openslide
- orc
- pango
- poppler
- webp
jobs:
allow_failures:
- os: osx
fast_finish: true
include:
- os: linux
dist: bionic
compiler: gcc
name: "Linux x64 (Ubuntu 18.04) - GCC 10"
addons:
apt:
sources:
- *common_sources
- ubuntu-toolchain-r-test
packages:
- *common_packages
- libmagick++-dev
- g++-10
env:
- JPEG=/usr
- JOBS=`nproc`
- WITH_MAGICK=yes
- CC="gcc-10"
- CXX="g++-10"
- LDSHARED="$CC -shared"
- CFLAGS="-Wcast-function-type"
cache: ccache
- os: linux
dist: bionic
compiler: clang
name: "Linux x64 (Ubuntu 18.04) - Clang 10 with ASan and UBSan"
addons:
apt:
sources:
- *common_sources
- sourceline: deb https://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main
key_url: https://apt.llvm.org/llvm-snapshot.gpg.key
packages:
- *common_packages
- clang-10
- libomp-10-dev
env:
- JPEG=/usr
- JOBS=`nproc`
- WITH_MAGICK=no
- CC="clang-10"
- CXX="clang++-10"
- LDSHARED="$CC -shared"
- CFLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer -fopenmp -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION"
- CXXFLAGS="$CFLAGS"
- LDFLAGS="-fsanitize=address,undefined -shared-libasan -fopenmp=libomp"
- ASAN_DSO=`$CC -print-file-name=libclang_rt.asan-x86_64.so`
- ASAN_SYMBOLIZER_PATH=`which llvm-symbolizer-10`
- ASAN_OPTIONS="suppressions=$TRAVIS_BUILD_DIR/suppressions/asan.supp"
- LSAN_OPTIONS="suppressions=$TRAVIS_BUILD_DIR/suppressions/lsan.supp"
- UBSAN_OPTIONS="suppressions=$TRAVIS_BUILD_DIR/suppressions/ubsan.supp:print_stacktrace=1"
- LD_LIBRARY_PATH="/usr/lib/llvm-10/lib:`dirname $ASAN_DSO`"
- DLCLOSE_PRELOAD="$TRAVIS_BUILD_DIR/dlclose.so"
before_script:
# workaround for https://github.com/google/sanitizers/issues/89
# otherwise libIlmImf-2_2.so ends up as <unknown module>
- echo -e '#include <stdio.h>\nint dlclose(void*handle){return 0;}' | $CC -shared -xc -odlclose.so -
cache: ccache
- os: osx
osx_image: xcode11
name: "macOS (10.14.6) - Xcode 11"
env:
- JPEG=/usr/local/opt/jpeg-turbo
- JOBS="`sysctl -n hw.ncpu`"
- WITH_MAGICK=no
- PATH="/usr/local/opt/ccache/libexec:$PATH"
- PKG_CONFIG_PATH="/usr/local/opt/jpeg-turbo/lib/pkgconfig:/usr/local/opt/libxml2/lib/pkgconfig:$PKG_CONFIG_PATH"
- HOMEBREW_NO_AUTO_UPDATE=1
- CC="clang"
- CXX="clang++"
cache: ccache
install:
- $PYTHON -m pip download --no-deps https://github.com/libvips/pyvips/archive/$PYVIPS_VERSION.tar.gz
- tar xf $PYVIPS_VERSION.tar.gz
- $PYTHON -m pip install --user --upgrade pyvips-$PYVIPS_VERSION/[test]
- ./autogen.sh
--disable-dependency-tracking
--disable-deprecated
--with-jpeg-includes=$JPEG/include
--with-jpeg-libraries=$JPEG/lib
--with-magick=$WITH_MAGICK
- make -j$JOBS -s
script:
- make -j$JOBS -s -k V=0 VERBOSE=1 check
- LD_LIBRARY_PATH="$PWD/libvips/.libs:$LD_LIBRARY_PATH"
DYLD_LIBRARY_PATH=$PWD/libvips/.libs
LD_PRELOAD="$ASAN_DSO $DLCLOSE_PRELOAD"
$PYTHON -m pytest -sv --log-cli-level=WARNING test/test-suite

View File

@ -16,6 +16,8 @@
- avoid NaN in mapim [afontenot]
- hist_find outputs a double histogram for large images [erdmann]
- fix ref leaks in mosaicing package
- run libvips leak test in CI
- add vips_fitsload_source()m vips_niftiload_source()
22/12/20 start 8.10.6
- don't seek on bad file descriptors [kleisauke]
@ -23,6 +25,8 @@
- revise ppmload, fixing a couple of small bugs
- signal error on EOF in jpegload more reliably [bozaro]
- better error detection in spngload [randy408]
- fix includes of glib headers in C++ [lovell]
- fix build with more modern librsvg [lovell]
18/12/20 started 8.10.5
- fix potential /0 in animated webp load [lovell]

View File

@ -1,6 +1,6 @@
# libvips : an image processing library
[![Test](https://github.com/libvips/libvips/workflows/Test/badge.svg)](https://github.com/libvips/libvips/actions?query=workflow%3ATest)
[![CI](https://github.com/libvips/libvips/workflows/CI/badge.svg)](https://github.com/libvips/libvips/actions)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/libvips.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=2&q=proj:libvips)
[![Coverity Status](https://scan.coverity.com/projects/6503/badge.svg)](https://scan.coverity.com/projects/jcupitt-libvips)
[![Gitter](https://badges.gitter.im/libvips/devchat.svg)](https://gitter.im/libvips/devchat?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)

View File

@ -616,11 +616,22 @@ vips_foreign_load_csv_source_build( VipsObject *object )
return( 0 );
}
static gboolean
vips_foreign_load_csv_source_is_a_source( VipsSource *source )
{
/* Detecting CSV files automatically is tricky. Define this method to
* prevent a warning, but users will need to run the csv loader
* explicitly.
*/
return( FALSE );
}
static void
vips_foreign_load_csv_source_class_init( VipsForeignLoadCsvFileClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
@ -628,6 +639,8 @@ vips_foreign_load_csv_source_class_init( VipsForeignLoadCsvFileClass *class )
object_class->nickname = "csvload_source";
object_class->build = vips_foreign_load_csv_source_build;
load_class->is_a_source = vips_foreign_load_csv_source_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,
_( "Source" ),
_( "Source to load from" ),

View File

@ -217,7 +217,9 @@ vips_fits_get_header( VipsFits *fits, VipsImage *out )
int status;
int bitpix;
int width, height, bands, format, type;
int width, height, bands;
VipsBandFormat format;
VipsInterpretation interpretation;
int keysexist;
int i;
@ -318,24 +320,24 @@ vips_fits_get_header( VipsFits *fits, VipsImage *out )
if( bands == 1 ) {
if( format == VIPS_FORMAT_USHORT )
type = VIPS_INTERPRETATION_GREY16;
interpretation = VIPS_INTERPRETATION_GREY16;
else
type = VIPS_INTERPRETATION_B_W;
interpretation = VIPS_INTERPRETATION_B_W;
}
else if( bands == 3 ) {
if( format == VIPS_FORMAT_USHORT )
type = VIPS_INTERPRETATION_RGB16;
interpretation = VIPS_INTERPRETATION_RGB16;
else
type = VIPS_INTERPRETATION_sRGB;
interpretation = VIPS_INTERPRETATION_sRGB;
}
else
type = VIPS_INTERPRETATION_MULTIBAND;
interpretation = VIPS_INTERPRETATION_MULTIBAND;
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL );
vips_image_init_fields( out,
width, height, bands,
format,
VIPS_CODING_NONE, type, 1.0, 1.0 );
VIPS_CODING_NONE, interpretation, 1.0, 1.0 );
/* Read all keys into meta.
*/
@ -517,7 +519,8 @@ int
vips__fits_read( const char *filename, VipsImage *out )
{
VipsImage *t;
int n_bands;
int bands;
VipsInterpretation interpretation;
VIPS_DEBUG_MSG( "fits2vips: reading \"%s\"\n", filename );
@ -531,22 +534,26 @@ vips__fits_read( const char *filename, VipsImage *out )
g_object_unref( t );
return( -1 );
}
n_bands = t->Bands;
bands = t->Bands;
interpretation = t->Type;
g_object_unref( t );
if( n_bands == 1 ) {
if( bands == 1 ) {
if( fits2vips( filename, out, 0 ) )
return( -1 );
}
else {
VipsImage **x;
VipsImage **y;
int i;
t = vips_image_new();
x = (VipsImage **) vips_object_local_array( VIPS_OBJECT( t ),
n_bands + 1 );
bands );
y = (VipsImage **) vips_object_local_array( VIPS_OBJECT( t ),
3 );
for( i = 0; i < n_bands; i++ ) {
for( i = 0; i < bands; i++ ) {
x[i] = vips_image_new();
if( fits2vips( filename, x[i], i ) ) {
g_object_unref( t );
@ -554,8 +561,11 @@ vips__fits_read( const char *filename, VipsImage *out )
}
}
if( vips_bandjoin( x, &x[n_bands], n_bands, NULL ) ||
vips_image_write( x[n_bands], out ) ) {
if( vips_bandjoin( x, &y[0], bands, NULL ) ||
vips_copy( y[0], &y[1],
"interpretation", interpretation,
NULL ) ||
vips_image_write( y[1], out ) ) {
g_object_unref( t );
return( -1 );
}

View File

@ -55,17 +55,85 @@
typedef struct _VipsForeignLoadFits {
VipsForeignLoad parent_object;
/* Filename for load.
/* Set by subclasses.
*/
char *filename;
VipsSource *source;
/* Filename from source.
*/
const char *filename;
} VipsForeignLoadFits;
typedef VipsForeignLoadClass VipsForeignLoadFitsClass;
G_DEFINE_TYPE( VipsForeignLoadFits, vips_foreign_load_fits,
G_DEFINE_ABSTRACT_TYPE( VipsForeignLoadFits, vips_foreign_load_fits,
VIPS_TYPE_FOREIGN_LOAD );
static void
vips_foreign_load_fits_dispose( GObject *gobject )
{
VipsForeignLoadFits *fits = (VipsForeignLoadFits *) gobject;
VIPS_UNREF( fits->source );
G_OBJECT_CLASS( vips_foreign_load_fits_parent_class )->
dispose( gobject );
}
static int
vips_foreign_load_fits_build( VipsObject *object )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsForeignLoadFits *fits =
(VipsForeignLoadFits *) object;
/* We can only open source which have an associated filename, since
* the fits library works in terms of filenames.
*/
if( fits->source ) {
fits->filename = vips_connection_filename( VIPS_CONNECTION(
fits->source ) );
if( !fits->filename ) {
vips_error( class->nickname, "%s",
_( "no filename available" ) );
return( -1 );
}
}
if( VIPS_OBJECT_CLASS( vips_foreign_load_fits_parent_class )->
build( object ) )
return( -1 );
return( 0 );
}
static VipsForeignFlags
vips_foreign_load_fits_get_flags_source( VipsSource *source )
{
return( VIPS_FOREIGN_PARTIAL );
}
static VipsForeignFlags
vips_foreign_load_fits_get_flags( VipsForeignLoad *load )
{
return( VIPS_FOREIGN_PARTIAL );
}
static VipsForeignFlags
vips_foreign_load_fits_get_flags_filename( const char *filename )
{
VipsSource *source;
VipsForeignFlags flags;
if( !(source = vips_source_new_from_file( filename )) )
return( 0 );
flags = vips_foreign_load_fits_get_flags_source( source );
VIPS_UNREF( source );
return( flags );
}
static int
vips_foreign_load_fits_header( VipsForeignLoad *load )
{
@ -103,32 +171,167 @@ vips_foreign_load_fits_class_init( VipsForeignLoadFitsClass *class )
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->dispose = vips_foreign_load_fits_dispose;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "fitsload";
object_class->description = _( "load a FITS image" );
object_class->nickname = "fitsload_base";
object_class->description = _( "FITS loader base class" );
object_class->build = vips_foreign_load_fits_build;
/* is_a() is not that quick ... lower the priority.
*/
foreign_class->priority = -50;
foreign_class->suffs = vips__fits_suffs;
load_class->get_flags_filename =
vips_foreign_load_fits_get_flags_filename;
load_class->get_flags = vips_foreign_load_fits_get_flags;
load_class->is_a = vips__fits_isfits;
load_class->header = vips_foreign_load_fits_header;
load_class->load = vips_foreign_load_fits_load;
}
static void
vips_foreign_load_fits_init( VipsForeignLoadFits *fits )
{
}
typedef struct _VipsForeignLoadFitsFile {
VipsForeignLoadFits parent_object;
/* Filename for load.
*/
char *filename;
} VipsForeignLoadFitsFile;
typedef VipsForeignLoadFitsClass VipsForeignLoadFitsFileClass;
G_DEFINE_TYPE( VipsForeignLoadFitsFile, vips_foreign_load_fits_file,
vips_foreign_load_fits_get_type() );
static int
vips_foreign_load_fits_file_build( VipsObject *object )
{
VipsForeignLoadFits *fits = (VipsForeignLoadFits *) object;
VipsForeignLoadFitsFile *file = (VipsForeignLoadFitsFile *) object;
if( file->filename &&
!(fits->source = vips_source_new_from_file( file->filename )) )
return( -1 );
if( VIPS_OBJECT_CLASS( vips_foreign_load_fits_file_parent_class )->
build( object ) )
return( -1 );
return( 0 );
}
static void
vips_foreign_load_fits_file_class_init( VipsForeignLoadFitsFileClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "fitsload";
object_class->description = _( "load a FITS image" );
object_class->build = vips_foreign_load_fits_file_build;
foreign_class->suffs = vips__fits_suffs;
load_class->is_a = vips__fits_isfits;
VIPS_ARG_STRING( class, "filename", 1,
_( "Filename" ),
_( "Filename to load from" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadFits, filename ),
G_STRUCT_OFFSET( VipsForeignLoadFitsFile, filename ),
NULL );
}
static void
vips_foreign_load_fits_init( VipsForeignLoadFits *fits )
vips_foreign_load_fits_file_init( VipsForeignLoadFitsFile *file )
{
}
typedef struct _VipsForeignLoadFitsSource {
VipsForeignLoadFits parent_object;
/* Load from a source.
*/
VipsSource *source;
} VipsForeignLoadFitsSource;
typedef VipsForeignLoadFitsClass VipsForeignLoadFitsSourceClass;
G_DEFINE_TYPE( VipsForeignLoadFitsSource, vips_foreign_load_fits_source,
vips_foreign_load_fits_get_type() );
static int
vips_foreign_load_fits_source_build( VipsObject *object )
{
VipsForeignLoadFits *fits = (VipsForeignLoadFits *) object;
VipsForeignLoadFitsSource *source =
(VipsForeignLoadFitsSource *) object;
if( source->source ) {
fits->source = source->source;
g_object_ref( fits->source );
}
if( VIPS_OBJECT_CLASS( vips_foreign_load_fits_source_parent_class )->
build( object ) )
return( -1 );
return( 0 );
}
static gboolean
vips_foreign_load_fits_source_is_a_source( VipsSource *source )
{
const char *filename;
return( (filename =
vips_connection_filename( VIPS_CONNECTION( source ) )) &&
vips__fits_isfits( filename ) );
}
static void
vips_foreign_load_fits_source_class_init(
VipsForeignLoadFitsSourceClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "fitsload_source";
object_class->description = _( "load FITS from a source" );
object_class->build = vips_foreign_load_fits_source_build;
load_class->is_a_source =
vips_foreign_load_fits_source_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,
_( "Source" ),
_( "Source to load from" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadFitsSource, source ),
VIPS_TYPE_SOURCE );
}
static void
vips_foreign_load_fits_source_init( VipsForeignLoadFitsSource *fits )
{
}
@ -166,3 +369,26 @@ vips_fitsload( const char *filename, VipsImage **out, ... )
return( result );
}
/**
* vips_fitsload_source:
* @source: source to load from
* @out: (out): decompressed image
* @...: %NULL-terminated list of optional named arguments
*
* Exactly as vips_fitsload(), but read from a source.
*
* Returns: 0 on success, -1 on error.
*/
int
vips_fitsload_source( VipsSource *source, VipsImage **out, ... )
{
va_list ap;
int result;
va_start( ap, out );
result = vips_call_split( "fitsload_source", ap, source, out );
va_end( ap );
return( result );
}

View File

@ -2117,7 +2117,8 @@ vips_foreign_operation_init( void )
extern GType vips_foreign_save_matrix_target_get_type( void );
extern GType vips_foreign_print_matrix_get_type( void );
extern GType vips_foreign_load_fits_get_type( void );
extern GType vips_foreign_load_fits_file_get_type( void );
extern GType vips_foreign_load_fits_source_get_type( void );
extern GType vips_foreign_save_fits_get_type( void );
extern GType vips_foreign_load_analyze_get_type( void );
@ -2182,7 +2183,8 @@ vips_foreign_operation_init( void )
extern GType vips_foreign_save_heif_buffer_get_type( void );
extern GType vips_foreign_save_heif_target_get_type( void );
extern GType vips_foreign_load_nifti_get_type( void );
extern GType vips_foreign_load_nifti_file_get_type( void );
extern GType vips_foreign_load_nifti_source_get_type( void );
extern GType vips_foreign_save_nifti_get_type( void );
extern GType vips_foreign_load_gif_file_get_type( void );
@ -2324,7 +2326,8 @@ vips_foreign_operation_init( void )
#endif /*ENABLE_MAGICKSAVE*/
#ifdef HAVE_CFITSIO
vips_foreign_load_fits_get_type();
vips_foreign_load_fits_file_get_type();
vips_foreign_load_fits_source_get_type();
vips_foreign_save_fits_get_type();
#endif /*HAVE_CFITSIO*/
@ -2333,7 +2336,8 @@ vips_foreign_operation_init( void )
#endif /*HAVE_OPENEXR*/
#ifdef HAVE_NIFTI
vips_foreign_load_nifti_get_type();
vips_foreign_load_nifti_file_get_type();
vips_foreign_load_nifti_source_get_type();
vips_foreign_save_nifti_get_type();
#endif /*HAVE_NIFTI*/

View File

@ -74,9 +74,13 @@
typedef struct _VipsForeignLoadNifti {
VipsForeignLoad parent_object;
/* Filename for load.
/* Source to load from (set by subclasses).
*/
char *filename;
VipsSource *source;
/* Filename from source.
*/
const char *filename;
/* The NIFTI image loaded to memory.
*/
@ -99,6 +103,7 @@ vips_foreign_load_nifti_dispose( GObject *gobject )
{
VipsForeignLoadNifti *nifti = (VipsForeignLoadNifti *) gobject;
VIPS_UNREF( nifti->source );
VIPS_UNREF( nifti->memory );
VIPS_FREEF( nifti_image_free, nifti->nim );
@ -107,38 +112,27 @@ vips_foreign_load_nifti_dispose( GObject *gobject )
}
static int
vips_foreign_load_nifti_is_a( const char *filename )
vips_foreign_load_nifti_build( VipsObject *object )
{
char *hfile;
znzFile fp;
nifti_1_header nhdr;
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsForeignLoadNifti *nifti = (VipsForeignLoadNifti *) object;
/* Unfortunately is_nifti_file() is very slow and produces lots of
* output. We have to make our own.
/* We can only open source which have an associated filename, since
* the nifti library works in terms of filenames.
*/
if( !(hfile = nifti_findhdrname( filename )) )
return( 0 );
fp = znzopen( hfile, "rb", nifti_is_gzfile( hfile ));
if( znz_isnull( fp ) ) {
free( hfile );
return( 0 );
if( nifti->source ) {
nifti->filename = vips_connection_filename( VIPS_CONNECTION(
nifti->source ) );
if( !nifti->filename ) {
vips_error( class->nickname, "%s",
_( "no filename available" ) );
return( -1 );
}
}
free( hfile );
(void) znzread( &nhdr, 1, sizeof( nhdr ), fp );
znzclose( fp );
/* Test for sanity both ways around. There's a thing to test for byte
* order in niftilib, but it's static :(
*/
if( nifti_hdr_looks_good( &nhdr ) )
return( 1 );
swap_nifti_header( &nhdr, FALSE );
if( nifti_hdr_looks_good( &nhdr ) )
return( 1 );
if( VIPS_OBJECT_CLASS( vips_foreign_load_nifti_parent_class )->
build( object ) )
return( -1 );
return( 0 );
}
@ -576,14 +570,6 @@ vips_foreign_load_nifti_load( VipsForeignLoad *load )
return( 0 );
}
const char *vips__nifti_suffs[] = {
".nii", ".nii.gz",
".hdr", ".hdr.gz",
".img", ".img.gz",
".nia", ".nia.gz",
NULL
};
static void
vips_foreign_load_nifti_class_init( VipsForeignLoadNiftiClass *class )
{
@ -596,29 +582,208 @@ vips_foreign_load_nifti_class_init( VipsForeignLoadNiftiClass *class )
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "niftiload";
object_class->nickname = "niftiload_base";
object_class->description = _( "load a NIFTI image" );
object_class->build = vips_foreign_load_nifti_build;
/* is_a() is not that quick ... lower the priority.
*/
foreign_class->priority = -50;
foreign_class->suffs = vips__nifti_suffs;
load_class->is_a = vips_foreign_load_nifti_is_a;
load_class->header = vips_foreign_load_nifti_header;
load_class->load = vips_foreign_load_nifti_load;
}
static void
vips_foreign_load_nifti_init( VipsForeignLoadNifti *nifti )
{
}
typedef struct _VipsForeignLoadNiftiFile {
VipsForeignLoadNifti parent_object;
/* Filename for load.
*/
char *filename;
} VipsForeignLoadNiftiFile;
typedef VipsForeignLoadNiftiClass VipsForeignLoadNiftiFileClass;
G_DEFINE_TYPE( VipsForeignLoadNiftiFile, vips_foreign_load_nifti_file,
vips_foreign_load_nifti_get_type() );
static int
vips_foreign_load_nifti_file_build( VipsObject *object )
{
VipsForeignLoadNifti *nifti = (VipsForeignLoadNifti *) object;
VipsForeignLoadNiftiFile *file = (VipsForeignLoadNiftiFile *) object;
if( file->filename &&
!(nifti->source =
vips_source_new_from_file( file->filename )) )
return( -1 );
if( VIPS_OBJECT_CLASS( vips_foreign_load_nifti_file_parent_class )->
build( object ) )
return( -1 );
return( 0 );
}
const char *vips_foreign_nifti_suffs[] = {
".nii", ".nii.gz",
".hdr", ".hdr.gz",
".img", ".img.gz",
".nia", ".nia.gz",
NULL
};
static int
vips_foreign_load_nifti_is_a( const char *filename )
{
char *hfile;
znzFile fp;
nifti_1_header nhdr;
/* Unfortunately is_nifti_file() is very slow and produces lots of
* output. We have to make our own.
*/
if( !(hfile = nifti_findhdrname( filename )) )
return( 0 );
fp = znzopen( hfile, "rb", nifti_is_gzfile( hfile ));
if( znz_isnull( fp ) ) {
free( hfile );
return( 0 );
}
free( hfile );
(void) znzread( &nhdr, 1, sizeof( nhdr ), fp );
znzclose( fp );
/* Test for sanity both ways around. There's a thing to test for byte
* order in niftilib, but it's static :(
*/
if( nifti_hdr_looks_good( &nhdr ) )
return( 1 );
swap_nifti_header( &nhdr, FALSE );
if( nifti_hdr_looks_good( &nhdr ) )
return( 1 );
return( 0 );
}
static void
vips_foreign_load_nifti_file_class_init(
VipsForeignLoadNiftiFileClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "niftiload";
object_class->description = _( "load NIfTI volume" );
object_class->build = vips_foreign_load_nifti_file_build;
foreign_class->suffs = vips_foreign_nifti_suffs;
load_class->is_a = vips_foreign_load_nifti_is_a;
VIPS_ARG_STRING( class, "filename", 1,
_( "Filename" ),
_( "Filename to load from" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadNifti, filename ),
G_STRUCT_OFFSET( VipsForeignLoadNiftiFile, filename ),
NULL );
}
static void
vips_foreign_load_nifti_init( VipsForeignLoadNifti *nifti )
vips_foreign_load_nifti_file_init( VipsForeignLoadNiftiFile *nifti )
{
}
typedef struct _VipsForeignLoadNiftiSource {
VipsForeignLoadNifti parent_object;
/* Load from a source.
*/
VipsSource *source;
} VipsForeignLoadNiftiSource;
typedef VipsForeignLoadNiftiClass VipsForeignLoadNiftiSourceClass;
G_DEFINE_TYPE( VipsForeignLoadNiftiSource, vips_foreign_load_nifti_source,
vips_foreign_load_nifti_get_type() );
static int
vips_foreign_load_nifti_source_build( VipsObject *object )
{
VipsForeignLoadNifti *nifti = (VipsForeignLoadNifti *) object;
VipsForeignLoadNiftiSource *source =
(VipsForeignLoadNiftiSource *) object;
if( source->source ) {
nifti->source = source->source;
g_object_ref( nifti->source );
}
if( VIPS_OBJECT_CLASS(
vips_foreign_load_nifti_source_parent_class )->
build( object ) )
return( -1 );
return( 0 );
}
static gboolean
vips_foreign_load_nifti_source_is_a_source( VipsSource *source )
{
const char *filename;
return( (filename =
vips_connection_filename( VIPS_CONNECTION( source ) )) &&
vips_foreign_load_nifti_is_a( filename ) );
}
static void
vips_foreign_load_nifti_source_class_init(
VipsForeignLoadNiftiSourceClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "niftiload_source";
object_class->description = _( "load NIfTI volumes" );
object_class->build = vips_foreign_load_nifti_source_build;
load_class->is_a_source =
vips_foreign_load_nifti_source_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,
_( "Source" ),
_( "Source to load from" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadNiftiSource, source ),
VIPS_TYPE_SOURCE );
}
static void
vips_foreign_load_nifti_source_init(
VipsForeignLoadNiftiSource *nifti )
{
}
@ -650,3 +815,26 @@ vips_niftiload( const char *filename, VipsImage **out, ... )
return( result );
}
/**
* vips_niftiload_source:
* @source: source to load from
* @out: (out): decompressed image
* @...: %NULL-terminated list of optional named arguments
*
* Exactly as vips_niftiload(), but read from a source.
*
* Returns: 0 on success, -1 on error.
*/
int
vips_niftiload_source( VipsSource *source, VipsImage **out, ... )
{
va_list ap;
int result;
va_start( ap, out );
result = vips_call_split( "niftiload_source", ap, source, out );
va_end( ap );
return( result );
}

View File

@ -428,7 +428,7 @@ vips_foreign_save_nifti_class_init( VipsForeignSaveNiftiClass *class )
object_class->description = _( "save image to nifti file" );
object_class->build = vips_foreign_save_nifti_build;
foreign_class->suffs = vips__nifti_suffs;
foreign_class->suffs = vips_foreign_nifti_suffs;
save_class->saveable = VIPS_SAVEABLE_ANY;
save_class->format_table = vips_nifti_bandfmt;

View File

@ -229,7 +229,7 @@ int vips__quantise_image( VipsImage *in,
VipsImage **index_out, VipsImage **palette_out,
int colours, int Q, double dither );
extern const char *vips__nifti_suffs[];
extern const char *vips_foreign_nifti_suffs[];
VipsBandFormat vips__foreign_nifti_datatype2BandFmt( int datatype );
int vips__foreign_nifti_BandFmt2datatype( VipsBandFormat fmt );

View File

@ -80,13 +80,6 @@
*/
#define RSVG_MAX_WIDTH (32767)
/* Old librsvg versions don't include librsvg-features.h by default.
* Newer versions deprecate direct inclusion.
*/
#ifndef LIBRSVG_FEATURES_H
#include <librsvg/librsvg-features.h>
#endif
/* A handy #define for we-will-handle-svgz.
*/
#if LIBRSVG_CHECK_FEATURE(SVGZ) && defined(HAVE_ZLIB)

View File

@ -33,11 +33,12 @@
#ifndef IM_DISPATCH_H
#define IM_DISPATCH_H
#include <glib-object.h>
#ifdef __cplusplus
extern "C" {
#endif /*__cplusplus*/
#include <glib-object.h>
#include <vips/vips.h>
#include <vips/util.h>

View File

@ -671,6 +671,8 @@ int vips_heifsave_target( VipsImage *in, VipsTarget *target, ... )
int vips_niftiload( const char *filename, VipsImage **out, ... )
__attribute__((sentinel));
int vips_niftiload_source( VipsSource *source, VipsImage **out, ... )
__attribute__((sentinel));
int vips_niftisave( VipsImage *in, const char *filename, ... )
__attribute__((sentinel));

View File

@ -114,9 +114,9 @@ void vips__threadpool_init( void );
void vips__cache_init( void );
void vips__print_renders( void );
void vips__type_leak( void );
int vips__print_renders( void );
int vips__type_leak( void );
int vips__object_leak( void );
typedef int (*im__fftproc_fn)( VipsImage *, VipsImage *, VipsImage * );
int im__fftproc( VipsImage *dummy,

View File

@ -80,10 +80,6 @@
#ifndef VIPS_VIPS_H
#define VIPS_VIPS_H
#ifdef __cplusplus
extern "C" {
#endif /*__cplusplus*/
#include <glib.h>
#include <glib/gstdio.h>
#include <gmodule.h>
@ -93,6 +89,10 @@ extern "C" {
*/
#include <gio/gio.h>
#ifdef __cplusplus
extern "C" {
#endif /*__cplusplus*/
/* If we're being parsed by SWIG, remove gcc attributes.
*/
#ifdef SWIG

View File

@ -200,7 +200,7 @@ vips_error_buffer_copy( void )
g_mutex_lock( vips__global_lock );
msg = g_strdup( vips_buf_all( &vips_error_buf ) );
vips_error_clear();
vips_buf_rewind( &vips_error_buf );
g_mutex_unlock( vips__global_lock );
return( msg );

View File

@ -643,13 +643,20 @@ vips_check_init( void )
vips_error_clear();
}
static void
static int
vips_leak( void )
{
char txt[1024];
VipsBuf buf = VIPS_BUF_STATIC( txt );
int n_leaks;
vips_object_print_all();
n_leaks = 0;
n_leaks += vips__object_leak();
n_leaks += vips__type_leak();
n_leaks += vips_tracked_get_allocs();
n_leaks += vips_tracked_get_mem();
n_leaks += vips_tracked_get_files();
if( vips_tracked_get_allocs() ||
vips_tracked_get_mem() ||
@ -664,21 +671,27 @@ vips_leak( void )
vips_buf_append_size( &buf, vips_tracked_get_mem_highwater() );
vips_buf_appends( &buf, "\n" );
if( strlen( vips_error_buffer() ) > 0 )
if( strlen( vips_error_buffer() ) > 0 ) {
vips_buf_appendf( &buf, "error buffer: %s",
vips_error_buffer() );
n_leaks += strlen( vips_error_buffer() );
}
if( vips__n_active_threads > 0 )
if( vips__n_active_threads > 0 ) {
vips_buf_appendf( &buf, "threads: %d not joined\n",
vips__n_active_threads );
n_leaks += vips__n_active_threads;
}
fprintf( stderr, "%s", vips_buf_all( &buf ) );
vips__print_renders();
n_leaks += vips__print_renders();
#ifdef DEBUG
vips_buffer_dump_all();
#endif /*DEBUG*/
return( n_leaks );
}
/**
@ -755,8 +768,9 @@ vips_shutdown( void )
{
static gboolean done = FALSE;
if( !done )
vips_leak();
if( !done &&
vips_leak() )
exit( 1 );
done = TRUE;
}

View File

@ -3167,23 +3167,34 @@ vips_object_print_all_cb( VipsObject *object, int *n, void *b )
return( NULL );
}
void
vips_object_print_all( void )
int
vips__object_leak( void )
{
int n_leaks;
n_leaks = 0;
/* Don't count static objects.
*/
if( vips__object_all &&
g_hash_table_size( vips__object_all ) >
vips_object_n_static() ) {
int n;
fprintf( stderr, "%d objects alive:\n",
g_hash_table_size( vips__object_all ) );
n = 0;
vips_object_map(
(VipsSListMap2Fn) vips_object_print_all_cb, &n, NULL );
(VipsSListMap2Fn) vips_object_print_all_cb,
&n_leaks, NULL );
}
vips__type_leak();
return( n_leaks );
}
void
vips_object_print_all( void )
{
(void) vips__object_leak();
(void) vips__type_leak();
}
static void *

View File

@ -1146,23 +1146,29 @@ vips_sink_screen( VipsImage *in, VipsImage *out, VipsImage *mask,
return( 0 );
}
void
int
vips__print_renders( void )
{
int n_leaks;
n_leaks = 0;
#ifdef VIPS_DEBUG_AMBER
if( render_num_renders > 0 )
if( render_num_renders > 0 ) {
printf( "%d active renders\n", render_num_renders );
n_leaks += render_num_renders;
}
#endif /*VIPS_DEBUG_AMBER*/
if( render_dirty_lock ) {
int n_dirty;
g_mutex_lock( render_dirty_lock );
n_dirty = g_slist_length( render_dirty_all );
if( n_dirty > 0 )
printf( "%d dirty renders\n", n_dirty );
n_leaks += g_slist_length( render_dirty_all );
if( render_dirty_all )
printf( "dirty renders\n" );
g_mutex_unlock( render_dirty_lock );
}
return( n_leaks );
}

View File

@ -285,9 +285,13 @@ vips_area_new( VipsCallbackFn free_fn, void *data )
return( area );
}
void
int
vips__type_leak( void )
{
int n_leaks;
n_leaks = 0;
if( vips_area_all ) {
GSList *p;
@ -298,8 +302,12 @@ vips__type_leak( void )
fprintf( stderr, "\t%p count = %d, bytes = %zd\n",
area, area->count, area->length );
n_leaks += 1;
}
}
return( n_leaks );
}
/**

View File

@ -3,5 +3,6 @@ leak:python3
leak:bash
leak:libfontconfig.so
leak:libglib-2.0.so
leak:libIlmImf-2_2.so
leak:libIlmImf-2_3.so
leak:libIlmThread-2_3.so
leak:libstdc++.so