Merge branch 'master' of https://github.com/libvips/libvips
This commit is contained in:
commit
1fde574a86
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
open_collective: libvips
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,4 +1,3 @@
|
||||
.pytest_cache
|
||||
compile
|
||||
.pytest_cache
|
||||
a.out
|
||||
@ -27,6 +26,8 @@ Makefile.in
|
||||
TAGS
|
||||
tags
|
||||
*.o
|
||||
*.a
|
||||
fuzz/*_fuzzer
|
||||
Vips-8.0.gir
|
||||
Vips-8.0.typelib
|
||||
.*.swp
|
||||
|
40
.travis.yml
40
.travis.yml
@ -8,12 +8,14 @@ before_script:
|
||||
--disable-dependency-tracking
|
||||
--with-jpeg-includes=$JPEG/include
|
||||
--with-jpeg-libraries=$JPEG/lib
|
||||
--with-magick=$WITH_MAGICK
|
||||
- make -j$JOBS -s
|
||||
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
|
||||
DYLD_LIBRARY_PATH=$PWD/libvips/.libs
|
||||
$PYTHON -m pytest -v test/test-suite
|
||||
LD_PRELOAD=$ASAN_DSO
|
||||
$PYTHON -m pytest -sv --log-cli-level=WARNING test/test-suite
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
@ -23,11 +25,41 @@ matrix:
|
||||
- os: linux
|
||||
sudo: required
|
||||
dist: xenial
|
||||
compiler: gcc
|
||||
env:
|
||||
- PYTHON=python2
|
||||
- PYVIPS_VERSION=master
|
||||
- JPEG=/usr
|
||||
- JOBS=`nproc`
|
||||
- WITH_MAGICK=yes
|
||||
cache: ccache
|
||||
|
||||
- os: linux
|
||||
sudo: required
|
||||
dist: xenial
|
||||
compiler: clang
|
||||
env:
|
||||
- PYTHON=python2
|
||||
- PYVIPS_VERSION=master
|
||||
- JPEG=/usr
|
||||
- JOBS=`nproc`
|
||||
- WITH_MAGICK=no
|
||||
- CFLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer -fopenmp -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION"
|
||||
- LDFLAGS="-fsanitize=address,undefined -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/suppressions/lsan.supp"
|
||||
- UBSAN_OPTIONS="suppressions=$TRAVIS_BUILD_DIR/suppressions/ubsan.supp"
|
||||
# comment these out, I get strange parse errors from asan for some
|
||||
# reason
|
||||
#
|
||||
# ASAN_OPTIONS="suppressions=$TRAVIS_BUILD_DIR/suppressions/asan.supp"
|
||||
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
|
||||
@ -37,6 +69,7 @@ matrix:
|
||||
- PYVIPS_VERSION=master
|
||||
- JPEG=/usr/local
|
||||
- JOBS="`sysctl -n hw.ncpu`"
|
||||
- WITH_MAGICK=yes
|
||||
- PATH="/usr/local/opt/ccache/libexec:$PATH"
|
||||
- HOMEBREW_NO_AUTO_UPDATE=1
|
||||
cache: ccache
|
||||
@ -45,7 +78,7 @@ addons:
|
||||
apt:
|
||||
update: true
|
||||
sources:
|
||||
# use imagemagick 6.9.7-4 instead than 6.8.9-9
|
||||
# use a more recent imagemagick instead of 6.8.9-9
|
||||
- sourceline: 'ppa:opencpu/imagemagick'
|
||||
# add support for HEIF files
|
||||
- sourceline: 'ppa:strukturag/libheif'
|
||||
@ -79,6 +112,7 @@ addons:
|
||||
- libgsf-1-dev
|
||||
- libopenslide-dev
|
||||
- libffi-dev
|
||||
- libiomp-dev
|
||||
homebrew:
|
||||
packages:
|
||||
- ccache
|
||||
|
50
ChangeLog
50
ChangeLog
@ -5,6 +5,56 @@
|
||||
- add "unlimited" flag to svgload
|
||||
- disable webp alpha output if all frames fill the canvas and are solid
|
||||
- add "compression" option to heifsave [lovell]
|
||||
- support webp and zstd compression in tiff
|
||||
- loaders use "minimise" to close input files earlier
|
||||
- integrate support for oss-fuzz [omira-sch]
|
||||
- add vips_switch() / vips_case() ... fast many-way ifthenelse
|
||||
- better const handling for arithmetic operators fixes comparisons against out
|
||||
of range values
|
||||
- sharpen restores input colourspace
|
||||
- handle alpha in heifload / heifsave [meyermarcel]
|
||||
- add @interpretation and @format to rawload
|
||||
- nifti load/save uses double for all floating point metadata
|
||||
- add vips_error_buffer_copy()
|
||||
- add VipsStream: a universal IO class for loaders and savers
|
||||
- jpeg, png, tiff (though not tiffsave), rad, svg, ppm and webp use the
|
||||
new IO class
|
||||
- rewritten ppm load/save is faster and uses less memory
|
||||
- add @no_strip option to dzsave [kalozka1]
|
||||
- add iiif layout to dzsave
|
||||
- fix use of resolution-unit metadata on tiff save [kayarre]
|
||||
- support TIFF CIELAB images with alpha [angelmixu]
|
||||
- support TIFF with premultiplied alpha in any band
|
||||
- block metadata changes on shared images [pvdz]
|
||||
|
||||
17/9/19 started 8.8.4
|
||||
- improve compatibility with older imagemagick versions
|
||||
- remove realpath, since it can fail on systems with grsec
|
||||
|
||||
31/8/19 started 8.8.3
|
||||
- revert sharpen restoring the input colourspace
|
||||
- xres/yres tiffsave params were in pixels/cm [f--f]
|
||||
|
||||
9/7/19 started 8.8.2
|
||||
- better early shutdown in readers
|
||||
- don't attempt to save large XMP to jpeg [tnextday]
|
||||
- always fetch HEIC metadata from the main image [zhoux2016]
|
||||
- fix loop in malformed ppm [Kyle-Kyle]
|
||||
- better support for PNGs with long comment names
|
||||
- fix build with GM
|
||||
- add locks for pdfium load
|
||||
- fix build with MSVC
|
||||
- fix a problem with shinkv tail processing [angelmixu]
|
||||
- fix a read one byte beyond buffer bug in jpegload
|
||||
- make GIF parsing less strict
|
||||
- better feof() handling in GIF load
|
||||
- clip coding and interpretation on vips image read
|
||||
- check image bounds for GIF load
|
||||
- prevent over-pre-shrink in thumbnail [kleisauke]
|
||||
- fix sharpen with sigma 0.5 [2h4dl]
|
||||
- sharpen restores input colourspace
|
||||
- verify bands/format for coded images
|
||||
- improve data_length handling for jpeg metadata
|
||||
|
||||
24/5/19 started 8.8.1
|
||||
- improve realpath() use on older libc
|
||||
|
@ -5,7 +5,8 @@ SUBDIRS = \
|
||||
po \
|
||||
man \
|
||||
doc \
|
||||
test
|
||||
test \
|
||||
fuzz
|
||||
|
||||
EXTRA_DIST = \
|
||||
m4 \
|
||||
@ -13,7 +14,7 @@ EXTRA_DIST = \
|
||||
autogen.sh \
|
||||
vips.pc.in \
|
||||
vips-cpp.pc.in \
|
||||
libvips.supp \
|
||||
suppressions \
|
||||
depcomp \
|
||||
README.md
|
||||
|
||||
|
133
README.md
133
README.md
@ -1,6 +1,7 @@
|
||||
# libvips : an image processing library
|
||||
|
||||
[](https://travis-ci.org/libvips/libvips)
|
||||
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=2&q=proj:libvips)
|
||||
[](https://scan.coverity.com/projects/jcupitt-libvips)
|
||||
|
||||
libvips is a [demand-driven, horizontally
|
||||
@ -47,8 +48,8 @@ a strange combination of a spreadsheet and an photo editor.
|
||||
|
||||
# Install
|
||||
|
||||
There are packages for most Unix-like operating systems, include macOS. Try
|
||||
your package manager.
|
||||
There are packages for most Unix-like operating systems, including
|
||||
macOS. Check your package manager.
|
||||
|
||||
There are binaries for Windows in
|
||||
[releases](https://github.com/libvips/libvips/releases).
|
||||
@ -63,7 +64,7 @@ We keep pre-baked tarballs in
|
||||
|
||||
Untar, then in the libvips directory you should just be able to do:
|
||||
|
||||
$ ./configure
|
||||
./configure
|
||||
|
||||
Check the summary at the end of `configure` carefully. libvips must have
|
||||
`build-essential`, `pkg-config`, `glib2.0-dev`, `libexpat1-dev`.
|
||||
@ -75,124 +76,114 @@ of the things that libvips can be configured to use.
|
||||
|
||||
Once `configure` is looking OK, compile and install with the usual:
|
||||
|
||||
$ make
|
||||
$ sudo make install
|
||||
make
|
||||
sudo make install
|
||||
|
||||
By default this will install files to `/usr/local`.
|
||||
|
||||
# Testing
|
||||
|
||||
Do a basic test of your build with:
|
||||
Run the test suite with:
|
||||
|
||||
$ make check
|
||||
|
||||
Run the libvips test suite with:
|
||||
|
||||
$ pytest
|
||||
make check
|
||||
|
||||
Run a specific test with:
|
||||
|
||||
$ pytest test/test-suite/test_foreign.py -k test_tiff
|
||||
pytest --verbose
|
||||
pytest test/test-suite/test_foreign.py -k test_tiff
|
||||
|
||||
# Building libvips from git
|
||||
|
||||
Clone the latest sources with:
|
||||
|
||||
$ git clone git://github.com/libvips/libvips.git
|
||||
git clone git://github.com/libvips/libvips.git
|
||||
|
||||
Building from git needs more packages -- you'll need at least `gtk-doc`
|
||||
and `gobject-introspection`, see the dependencies section below. For example:
|
||||
|
||||
$ brew install gtk-doc
|
||||
brew install gtk-doc
|
||||
|
||||
Then build the build system with:
|
||||
|
||||
$ ./autogen.sh
|
||||
./autogen.sh --prefix=/home/john/vips
|
||||
|
||||
Debug build:
|
||||
|
||||
$ CFLAGS="-g -Wall" CXXFLAGS="-g -Wall" \
|
||||
./configure --prefix=/home/john/vips --enable-debug
|
||||
$ make
|
||||
$ make install
|
||||
CFLAGS="-g -Wall" CXXFLAGS="-g -Wall" \
|
||||
./configure --prefix=/home/john/vips --enable-debug
|
||||
make
|
||||
make install
|
||||
|
||||
Leak check:
|
||||
Leak check. Use the suppressions file `supp/valgrind.supp`.
|
||||
|
||||
$ export G_DEBUG=gc-friendly
|
||||
$ valgrind --suppressions=libvips.supp \
|
||||
--leak-check=yes \
|
||||
vips ... > vips-vg.log 2>&1
|
||||
export G_DEBUG=gc-friendly
|
||||
valgrind --suppressions=vips-x.y.z/supp/valgrind.supp \
|
||||
--leak-check=yes \
|
||||
vips ... > vips-vg.log 2>&1
|
||||
|
||||
Memory error debug:
|
||||
|
||||
$ valgrind --vgdb=yes --vgdb-error=0 vips ...
|
||||
valgrind --vgdb=yes --vgdb-error=0 vips ...
|
||||
|
||||
valgrind threading check:
|
||||
|
||||
$ valgrind --tool=helgrind vips ... > vips-vg.log 2>&1
|
||||
valgrind --tool=helgrind vips ... > vips-vg.log 2>&1
|
||||
|
||||
Clang build:
|
||||
|
||||
$ CC=clang CXX=clang++ ./configure --prefix=/home/john/vips
|
||||
CC=clang CXX=clang++ ./configure --prefix=/home/john/vips
|
||||
|
||||
Clang static analysis:
|
||||
|
||||
$ scan-build ./configure --disable-introspection --disable-debug
|
||||
$ scan-build -o scan -v make
|
||||
$ scan-view scan/2013-11-22-2
|
||||
scan-build ./configure --disable-introspection --disable-debug
|
||||
scan-build -o scan -v make
|
||||
scan-view scan/2013-11-22-2
|
||||
|
||||
Clang dynamic analysis:
|
||||
|
||||
$ FLAGS="-g -O1 -fno-omit-frame-pointer"
|
||||
$ CC=clang CXX=clang++ LD=clang \
|
||||
CFLAGS="$FLAGS" CXXFLAGS="$FLAGS" LDFLAGS=-fsanitize=address \
|
||||
./configure --prefix=/home/john/vips
|
||||
FLAGS="-g -O1 -fno-omit-frame-pointer"
|
||||
CC=clang CXX=clang++ LD=clang \
|
||||
CFLAGS="$FLAGS" CXXFLAGS="$FLAGS" LDFLAGS=-fsanitize=address \
|
||||
./configure --prefix=/home/john/vips
|
||||
|
||||
$ FLAGS="-O1 -g -fsanitize=thread"
|
||||
$ FLAGS="$FLAGS -fPIC"
|
||||
$ FLAGS="$FLAGS -fno-omit-frame-pointer -fno-optimize-sibling-calls"
|
||||
$ CC=clang CXX=clang++ LD=clang \
|
||||
FLAGS="-O1 -g -fsanitize=thread"
|
||||
FLAGS="$FLAGS -fPIC"
|
||||
FLAGS="$FLAGS -fno-omit-frame-pointer -fno-optimize-sibling-calls"
|
||||
CC=clang CXX=clang++ LD=clang \
|
||||
CFLAGS="$FLAGS" CXXFLAGS="$FLAGS" \
|
||||
LDFLAGS="-fsanitize=thread -fPIC" \
|
||||
./configure --prefix=/home/john/vips \
|
||||
--without-magick \
|
||||
--disable-introspection
|
||||
$ G_DEBUG=gc-friendly vips copy ~/pics/k2.jpg x.jpg >& log
|
||||
G_DEBUG=gc-friendly vips copy ~/pics/k2.jpg x.jpg >& log
|
||||
|
||||
Build with the GCC auto-vectorizer and diagnostics (or just -O3):
|
||||
|
||||
$ FLAGS="-O2 -march=native -ffast-math"
|
||||
$ FLAGS="$FLAGS -ftree-vectorize -fdump-tree-vect-details"
|
||||
$ CFLAGS="$FLAGS" CXXFLAGS="$FLAGS" \
|
||||
FLAGS="-O2 -march=native -ffast-math"
|
||||
FLAGS="$FLAGS -ftree-vectorize -fdump-tree-vect-details"
|
||||
CFLAGS="$FLAGS" CXXFLAGS="$FLAGS" \
|
||||
./configure --prefix=/home/john/vips
|
||||
|
||||
Static analysis with:
|
||||
|
||||
$ cppcheck --force --enable=style . &> cppcheck.log
|
||||
|
||||
# Dependencies
|
||||
|
||||
libvips has to have `glib2.0-dev`. Other dependencies are optional, see below.
|
||||
libvips has to have `glib2.0-dev` and `libexpat1-dev`. Other dependencies
|
||||
are optional.
|
||||
|
||||
# Optional dependencies
|
||||
## Optional dependencies
|
||||
|
||||
If suitable versions are found, libvips will add support for the following
|
||||
libraries automatically. See `./configure --help` for a set of flags to
|
||||
control library detection. Packages are generally found with `pkg-config`,
|
||||
so make sure that is working.
|
||||
|
||||
libtiff, giflib and libjpeg do not usually use `pkg-config` so libvips looks for
|
||||
them in the default path and in `$prefix`. If you have installed your own
|
||||
versions of these libraries in a different location, libvips will not see
|
||||
them. Use switches to libvips configure like:
|
||||
Libraries like giflib and nifti do not use `pkg-config` so libvips will also
|
||||
look for them in the default path and in `$prefix`. If you have installed
|
||||
your own versions of these libraries in a different location, libvips will
|
||||
not see them. Use switches to libvips configure like:
|
||||
|
||||
./configure --prefix=/Users/john/vips \
|
||||
--with-giflib-includes=/opt/local/include \
|
||||
--with-giflib-libraries=/opt/local/lib \
|
||||
--with-tiff-includes=/opt/local/include \
|
||||
--with-tiff-libraries=/opt/local/lib \
|
||||
--with-jpeg-includes=/opt/local/include \
|
||||
--with-jpeg-libraries=/opt/local/lib
|
||||
--with-giflib-includes=/opt/local/include \
|
||||
--with-giflib-libraries=/opt/local/lib
|
||||
|
||||
or perhaps:
|
||||
|
||||
@ -200,8 +191,6 @@ or perhaps:
|
||||
CXXFLAGS="-g -Wall -I/opt/local/include -L/opt/local/lib" \
|
||||
./configure --prefix=/Users/john/vips
|
||||
|
||||
to get libvips to see your builds.
|
||||
|
||||
### libjpeg
|
||||
|
||||
The IJG JPEG library. Use the `-turbo` version if you can.
|
||||
@ -311,9 +300,25 @@ files: Aperio, Hamamatsu, Leica, MIRAX, Sakura, Trestle, and Ventana.
|
||||
|
||||
If available, libvips can load and save HEIC images.
|
||||
|
||||
# Disclaimer
|
||||
# Contributors
|
||||
|
||||
No guarantees of performance accompany this software, nor is any
|
||||
responsibility assumed on the part of the authors. Please read the licence
|
||||
agreement.
|
||||
### Code Contributors
|
||||
|
||||
This project exists thanks to all the people who contribute.
|
||||
|
||||
<a href="https://github.com/libvips/libvips/graphs/contributors"><img src="https://opencollective.com/libvips/contributors.svg?width=890&button=false" /></a>
|
||||
|
||||
### Organizations
|
||||
|
||||
Support this project with your organization. Your logo will show up here with a link to your website.
|
||||
|
||||
<a href="https://opencollective.com/libvips/organization/0/website"><img src="https://opencollective.com/libvips/organization/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/libvips/organization/1/website"><img src="https://opencollective.com/libvips/organization/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/libvips/organization/2/website"><img src="https://opencollective.com/libvips/organization/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/libvips/organization/3/website"><img src="https://opencollective.com/libvips/organization/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/libvips/organization/4/website"><img src="https://opencollective.com/libvips/organization/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/libvips/organization/5/website"><img src="https://opencollective.com/libvips/organization/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/libvips/organization/6/website"><img src="https://opencollective.com/libvips/organization/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/libvips/organization/7/website"><img src="https://opencollective.com/libvips/organization/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/libvips/organization/8/website"><img src="https://opencollective.com/libvips/organization/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/libvips/organization/9/website"><img src="https://opencollective.com/libvips/organization/9/avatar.svg"></a>
|
||||
|
439
TODO
439
TODO
@ -1,439 +0,0 @@
|
||||
- try
|
||||
|
||||
$ vips gaussmat x.mat 0.1 0.1
|
||||
(vips:28376): GLib-GObject-WARNING **: value "-1" of type 'gint' is invalid or out of range for property 'width' of type 'gint'
|
||||
(vips:28376): GLib-GObject-WARNING **: value "-1" of type 'gint' is invalid or out of range for property 'height' of type 'gint'
|
||||
$ more x.mat
|
||||
1 1 0 0
|
||||
5.55604e+180
|
||||
|
||||
check numeric range of SIGMA args, we should standardize
|
||||
|
||||
- rewind should break more things ... does it remove upsteam/downstream? does it
|
||||
just need to remove reorder links?
|
||||
|
||||
perhaps reorder should use upstream/downstream, then it will be broken anyway
|
||||
|
||||
- not sure about utf8 error messages on win
|
||||
|
||||
- strange:
|
||||
|
||||
$ vips similarity --scale 0.33 k2.jpg x.v
|
||||
$ vipsheader k2.jpg
|
||||
k2.jpg: 1450x2048 uchar, 3 bands, srgb, jpegload
|
||||
$ vipsheader x.v
|
||||
x.v: 478x676 uchar, 3 bands, srgb, jpegload
|
||||
|
||||
1450 * 0.33 = 478.5 ... this was rounded down
|
||||
2048 * 0.33 = 675.84 ... this was rounded up
|
||||
|
||||
- add APPROX convsep test?
|
||||
|
||||
- add more webp tests to py suite
|
||||
|
||||
- try moving some more of the CLI tests to py
|
||||
|
||||
- colour needs to split _build() into preprocess / process / postprocess
|
||||
phases
|
||||
|
||||
in icc_import, for example, we want to check that the supplied profile is
|
||||
compatible with the input image as it will be when unpacked and ready for
|
||||
process_line
|
||||
|
||||
see vips_image_expected_bands() in icc_transform.c for the current hacky
|
||||
solution
|
||||
|
||||
|
||||
|
||||
- use the incremental webp decoding api to support seq for webp images
|
||||
|
||||
https://developers.google.com/speed/webp/docs/api#decodingadvancedapi
|
||||
|
||||
doesn't seem to be possible
|
||||
|
||||
- does ruby need to unpack RefString as well? what about C++?
|
||||
|
||||
- are the mosaic functions calling vips_fastcor()? it must be very slow
|
||||
|
||||
add vips_fastcor_direct()
|
||||
|
||||
nope .. it's im_chkpair.c:im_correl()
|
||||
|
||||
im_extract_area(main)
|
||||
im_extract_area(sub)
|
||||
im_extract_band(main)
|
||||
im_extract_band(sub)
|
||||
im_spcor(sub)
|
||||
im_maxpos(sub)
|
||||
|
||||
then im__chkpair() runs that 20 times, then loops ... oh dear
|
||||
|
||||
- perhaps im_maxpos_subpel() / im_minpos_subpel() should be undeprecated,
|
||||
useful with vips_fastcor()
|
||||
|
||||
|
||||
|
||||
- why can't we do
|
||||
|
||||
im = Vips.Image.new_from_file("/data/john/pics/k2.jpg", access = "sequential")
|
||||
|
||||
no idea ... this works fine:
|
||||
|
||||
im.embed(10, 10, 100, 100, extend = "copy")
|
||||
|
||||
test:
|
||||
|
||||
op = Vips.Operation.new("embed")
|
||||
op.props.__setattr__("extend", "copy")
|
||||
op = Vips.Operation.new("jpegload")
|
||||
op.props.__setattr__("access", "sequential")
|
||||
|
||||
first setattr works fine, second fails with invalid literal
|
||||
|
||||
|
||||
|
||||
|
||||
- test other cpp arg types
|
||||
|
||||
input int works
|
||||
input double
|
||||
input enum works
|
||||
input image works
|
||||
input doublevec
|
||||
input imagevec
|
||||
input blob
|
||||
|
||||
output int
|
||||
output double works
|
||||
output enum
|
||||
output image works
|
||||
output doublevec
|
||||
output imagevec
|
||||
output blob
|
||||
|
||||
we probably need to unpack the ink back to double before blending
|
||||
|
||||
|
||||
|
||||
- ink to vec etc must have a way to give a complex constant
|
||||
|
||||
eg. drawink needs a --ink_imag option with the imaginary components of the
|
||||
ink
|
||||
|
||||
look for uses of vips__vector_to_ink() and add extra params to other places
|
||||
too, eg. vips_embed(), vips_insert() etc.
|
||||
|
||||
- vips__ink_to_vector() needs an optional imag return
|
||||
|
||||
- vips_getpoint() needs an optional imag return
|
||||
|
||||
- add porter-duff compositing, see
|
||||
|
||||
https://github.com/libvips/ruby-vips/issues/28
|
||||
|
||||
- now vips_linear() has uchar output, can we do something with orc?
|
||||
|
||||
- do restrict on some more packages, we've just done arithmetic so far
|
||||
|
||||
also resample, colour, some of conversion, create,
|
||||
|
||||
- maybe avg?
|
||||
|
||||
but avg doesn't subclass arithmetic, so we can't
|
||||
|
||||
- for interpolate, we'd need to be able to unroll the vector, so the
|
||||
interpolator would need to be built for the bands / stride / type of the
|
||||
image
|
||||
|
||||
need new API For this since interpolators currently work for any image
|
||||
|
||||
- vips_gaussblur() should switch to float prec if given a float image?
|
||||
|
||||
same for vips_conv()?
|
||||
|
||||
maybe precision is a dumb thing
|
||||
|
||||
- support --strip for other writers
|
||||
|
||||
- vipsthumbnail could shrink-on-load openslide and pyr tiff as well?
|
||||
|
||||
we have "shrink" for jpegload, move this into the base loader
|
||||
|
||||
support it for tiff and openslide as well
|
||||
|
||||
use it from nip2 for zooming? only if the partial flag is set though, we
|
||||
don't want to use it on jpg files
|
||||
|
||||
|
||||
|
||||
- quadratic doesn't work for order 3
|
||||
|
||||
start to get jaggies on lines --- the 3rd differential isn't being
|
||||
initialised correctly for the sub-region?
|
||||
|
||||
seems fine vertically, only get errors on horizontal tile boundaries
|
||||
|
||||
because we step across tiles left to right: y doesn't change, only x does
|
||||
|
||||
not sure it works for order 2 either, we are seeing interpolation errors
|
||||
on image edges
|
||||
|
||||
|
||||
mosaic
|
||||
======
|
||||
|
||||
- balance should use new meta stuff
|
||||
|
||||
- histogram balance option?
|
||||
|
||||
|
||||
resample
|
||||
========
|
||||
|
||||
- check mosaic1, global_balance, similarity etc. use of im__affine
|
||||
|
||||
how can we move them to im_affinei ?
|
||||
|
||||
- perspective transform with a matrix ... base it on the Lenz transformer, but
|
||||
partial
|
||||
|
||||
|
||||
foreign
|
||||
=======
|
||||
|
||||
- magick2vips should spot ICC profiles and attach them as meta
|
||||
|
||||
- interlaced jpg needs massive memory, we should have two jpg read modes, like
|
||||
png
|
||||
|
||||
- add more sequential mode readers
|
||||
|
||||
$ grep -l write_line *.c
|
||||
csv.c
|
||||
matlab.c
|
||||
openexr2vips.c
|
||||
ppm.c
|
||||
radiance.c
|
||||
|
||||
- foreign docs come up as "VipsForeignSave", annoying, why?
|
||||
|
||||
- add nifti support
|
||||
|
||||
http://niftilib.sourceforge.net/
|
||||
|
||||
- add matlab write
|
||||
|
||||
- im_exr2vips can now use c++ api
|
||||
|
||||
see TODO notes in openexr read (though they all need more openexr C API)
|
||||
|
||||
consider openexr write
|
||||
|
||||
- magick should set some header field for n_frames and frame_height? see also
|
||||
analyze
|
||||
|
||||
- im_csv2vips() could use "-" for filename to mean stdin
|
||||
|
||||
but then we'd have to read to a malloced buffer of some sort rather than an
|
||||
image, since we might need to grow it during the read, since we couldn't
|
||||
then seek
|
||||
|
||||
|
||||
packaging
|
||||
=========
|
||||
|
||||
- test _O_TEMPORARY thing on Windows
|
||||
|
||||
|
||||
convolution
|
||||
===========
|
||||
|
||||
- revisit orc conv
|
||||
|
||||
use an 8.8 accumulator ... build the scale into the 8.8 coeffs ... no div at
|
||||
the end, just a shift
|
||||
|
||||
need 8 x 8.8 -> 8.8 for each coeff though
|
||||
|
||||
- im_conv()/im_morph() could have more than 10 programs? try 20 and see if we
|
||||
still have a speedup
|
||||
|
||||
make a base class for vector area operations with a matrix with three vfuncs
|
||||
for init / generate code for one element / end and a gslist of programs, use
|
||||
that as the base for morph and conv
|
||||
|
||||
wait for vipsobject for this
|
||||
|
||||
- we have aconv and aconvsep
|
||||
|
||||
test timing, make sure it;s worth having a separate aconvsep version
|
||||
|
||||
if it is, make im_aconvsep an optimisation: call im_aconvsep_raw() from
|
||||
vips_conv() if mask width or height == 1 and prec == APPROX
|
||||
|
||||
now we can get rid of im_aconvsep() since it's just vips_convsep() with prec
|
||||
set to approx
|
||||
|
||||
aconv needs some more work, get it going at least with gaussian
|
||||
|
||||
|
||||
arithmetic
|
||||
==========
|
||||
|
||||
- HAVE_HYPOT could define a hypot() macro?
|
||||
|
||||
- fix a better NaN policy
|
||||
|
||||
should we not generate images containing NaN (eg. divide tries to avoid /0),
|
||||
or should vips_max() etc. try to avoid NaN in images (eg. vips_max() takes a
|
||||
lot a care to skip NaN, though vips_stats() does not)?
|
||||
|
||||
|
||||
iofuncs
|
||||
=======
|
||||
|
||||
- need vips_image_invalidate_area()
|
||||
|
||||
- look at libpeas for plugin support
|
||||
|
||||
http://live.gnome.org/Libpeas
|
||||
|
||||
- how about
|
||||
|
||||
vips max add[babe.jpg,babe2.jpg]
|
||||
|
||||
does that make any sense?
|
||||
|
||||
vips copy add[babe.jpg,add[babe2.jpg,babe3.jpg]] sum.v
|
||||
|
||||
perhaps use curly brackets for code?
|
||||
|
||||
vips max add{babe.jpg,babe2.jpg}
|
||||
|
||||
no brackets or square brackets for options
|
||||
|
||||
- transform_g_string_array_image() can't handle quoted strings, so filenames
|
||||
with spaces will break
|
||||
|
||||
is there an easy fix? can we reuse code from the csv parser?
|
||||
|
||||
the csv parser just parses FILE* streams, we'd need to break it out
|
||||
|
||||
- note member free stuff in vipsobject docs
|
||||
|
||||
should boxed get freed in finalise rather than dispose?
|
||||
|
||||
vipsobject has few docs atm :(
|
||||
|
||||
- vips_object_set_argument_from_string() needs more arg types
|
||||
|
||||
must be some way to make this more automatic
|
||||
|
||||
- generate the code for vips_add() etc. automatically? it might be
|
||||
nice to have them all in one place at least
|
||||
|
||||
- what does G_UNLIKELY() do? can we use it?
|
||||
|
||||
- look into G_GNUC_DEPRECATED for back compat in vips8
|
||||
|
||||
- should im_rwcheck() copy to disc?
|
||||
|
||||
maybe im_rwcheck_disc() copies to im->filename and maps that
|
||||
|
||||
rather awkward to do atm with the way check.c is structured
|
||||
|
||||
|
||||
swig
|
||||
====
|
||||
|
||||
- swig is not wrapping im_project() correctly ... returns an extra VImage via
|
||||
a param
|
||||
|
||||
- doc strings would be nice, read the SWIG notes on this
|
||||
|
||||
|
||||
new bindings
|
||||
============
|
||||
|
||||
- new binding is still missing constants
|
||||
|
||||
how do boxed types work? confusing
|
||||
|
||||
we need to be able to make a VipsArrayDouble
|
||||
|
||||
- Vips.Image has members like chain, __subclasshook__ etc etc, are we
|
||||
really subclassing it correctly?
|
||||
|
||||
- add __add__ etc overloads
|
||||
|
||||
|
||||
freq_filt
|
||||
=========
|
||||
|
||||
- fft with odd width or height is broken ... DC ends up in the wrong place
|
||||
|
||||
|
||||
libvipsCC
|
||||
=========
|
||||
|
||||
- need new C++ API
|
||||
|
||||
- need an im_init_world() for C++ which does cmd-line args too, so C++ progs
|
||||
can get --vips-progress and stuff automatically
|
||||
|
||||
|
||||
tools
|
||||
=====
|
||||
|
||||
- need a way to make the vips.1 etc. man pages
|
||||
|
||||
gtk has things like docs/reference/gtk/gtk-update-icon-cache.xml and man
|
||||
pages are made from that with xslt
|
||||
|
||||
- get rid of a lot of the command-line programs, who wants to write a man page
|
||||
for batch_image_convert etc yuk
|
||||
|
||||
- can we make man pages for the API as well? probably not from googling a bit
|
||||
|
||||
- rename header, edvips as vipsheader, vipsedit
|
||||
|
||||
maybe have back compat links?
|
||||
|
||||
|
||||
new operations
|
||||
==============
|
||||
|
||||
- bilateral filtering, see:
|
||||
|
||||
http://en.wikipedia.org/wiki/Bilateral_filter
|
||||
http://www.shellandslate.com/fastmedian.html
|
||||
http://people.csail.mit.edu/sparis/bf_course/
|
||||
|
||||
also a mail from Martin Breidt has links to several fast free C
|
||||
implementations
|
||||
|
||||
- http://en.wikipedia.org/wiki/Otsu%27s_method
|
||||
|
||||
- non-linear sharpen: replace each pixel by the lightest or darkest neighbour
|
||||
depending on which is closer in value
|
||||
|
||||
- look at
|
||||
|
||||
There is an order 1 algorithm for doing medians over boxes (truly O(1)
|
||||
per pixel: I checked it carefully; it's like doing means over boxes in
|
||||
order 1 per pixel) in OpenCV since February 2012 I think, due to
|
||||
Perreault (and Hebert).
|
||||
|
||||
It appears to be well respected, at least for 8-bit medians. Very
|
||||
memory intensive. Simple and elegant. No clue if it fits VIPS well
|
||||
(probably not?).
|
||||
|
||||
Article: nomis80.org/ctmf.pdf
|
||||
|
||||
- see
|
||||
|
||||
http://www.dentistry.bham.ac.uk/landinig/software/cdeconv/cdeconv.html
|
||||
|
||||
http://www.nature.com/srep/2015/150730/srep12096/full/srep12096.html
|
||||
|
||||
sounds useful for BM?
|
287
configure.ac
287
configure.ac
@ -449,7 +449,6 @@ AC_CHECK_FUNCS([getcwd gettimeofday getwd memset munmap putenv realpath strcasec
|
||||
AC_CHECK_LIB(m,cbrt,[AC_DEFINE(HAVE_CBRT,1,[have cbrt() in libm.])])
|
||||
AC_CHECK_LIB(m,hypot,[AC_DEFINE(HAVE_HYPOT,1,[have hypot() in libm.])])
|
||||
AC_CHECK_LIB(m,atan2,[AC_DEFINE(HAVE_ATAN2,1,[have atan2() in libm.])])
|
||||
AC_CHECK_LIB([pthread], [pthread_setattr_default_np], [AC_DEFINE(HAVE_PTHREAD_DEFAULT_NP,1,[have pthread_setattr_default_np() in pthread.])])
|
||||
|
||||
# have to have these
|
||||
# need glib 2.6 for GOption
|
||||
@ -476,8 +475,18 @@ PKG_CHECK_MODULES(CONTEXT_GET_HELP, glib-2.0 >= 2.14,
|
||||
]
|
||||
)
|
||||
|
||||
# from 2.15 we have GIO
|
||||
PKG_CHECK_MODULES(GIO, glib-2.0 >= 2.15,
|
||||
[AC_DEFINE(HAVE_GIO,1,
|
||||
[define if your glib has GIO.]
|
||||
)
|
||||
],
|
||||
[:
|
||||
]
|
||||
)
|
||||
|
||||
# from 2.28 we have a monotonic timer
|
||||
PKG_CHECK_MODULES(MONOTONIC, glib-2.0 >= 2.28,
|
||||
PKG_CHECK_MODULES(MONOTONIC_TIME, glib-2.0 >= 2.28,
|
||||
[AC_DEFINE(HAVE_MONOTONIC_TIME,1,
|
||||
[define if your glib has g_get_monotonic_time().]
|
||||
)
|
||||
@ -486,6 +495,20 @@ PKG_CHECK_MODULES(MONOTONIC, glib-2.0 >= 2.28,
|
||||
]
|
||||
)
|
||||
|
||||
# from 2.62 we have datetime
|
||||
PKG_CHECK_MODULES(DATE_TIME_FORMAT_ISO8601, glib-2.0 >= 2.62,
|
||||
[AC_DEFINE(HAVE_DATE_TIME_FORMAT_ISO8601,1,
|
||||
[define if your glib has g_date_time_format_iso8601().]
|
||||
)
|
||||
],
|
||||
[:
|
||||
]
|
||||
)
|
||||
|
||||
# the old threading system
|
||||
PKG_CHECK_MODULES(GTHREAD, gthread-2.0)
|
||||
PACKAGES_USED="$PACKAGES_USED gthread-2.0"
|
||||
|
||||
# from 2.32 there are a new set of thread functions, annoyingly
|
||||
PKG_CHECK_MODULES(THREADS, glib-2.0 >= 2.32,
|
||||
[AC_DEFINE(HAVE_MUTEX_INIT,1,[define if your glib has g_mutex_init().])
|
||||
@ -496,12 +519,24 @@ PKG_CHECK_MODULES(THREADS, glib-2.0 >= 2.32,
|
||||
[define if your glib has g_value_get_schar().]
|
||||
)
|
||||
],
|
||||
[# the old threading system ... we need to link against gthread
|
||||
PKG_CHECK_MODULES(GTHREAD, gthread-2.0)
|
||||
PACKAGES_USED="$PACKAGES_USED gthread-2.0"
|
||||
[:
|
||||
]
|
||||
)
|
||||
|
||||
# if available, we use pthread_setattr_default_np() to raise the per-thread
|
||||
# stack size ... musl (libc on Alpine), for example, has a very small stack per
|
||||
# thread by default
|
||||
save_pthread_LIBS="$LIBS"
|
||||
save_pthread_CFLAGS="$CFLAGS"
|
||||
LIBS="$LIBS $GTHREAD_LIBS"
|
||||
CFLAGS="$CFLAGS $GTHREAD_CFLAGS"
|
||||
AC_CHECK_FUNC(pthread_setattr_default_np,
|
||||
[AC_DEFINE(HAVE_PTHREAD_DEFAULT_NP,1,[have pthread_setattr_default_np().])
|
||||
]
|
||||
)
|
||||
LIBS="$save_pthread_LIBS"
|
||||
CFLAGS="$save_pthread_CFLAGS"
|
||||
|
||||
# from 2.36 the type system inits itself
|
||||
PKG_CHECK_MODULES(TYPE_INIT, glib-2.0 < 2.36,
|
||||
[AC_DEFINE(HAVE_TYPE_INIT,1,[define if your glib needs g_type_init().])
|
||||
@ -547,18 +582,6 @@ if test x"$expat_found" = x"no"; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# enable vips7 C++ binding ... this defaults off, the vips8 C++ binding
|
||||
# defaults on
|
||||
AC_ARG_ENABLE([cpp7],
|
||||
AS_HELP_STRING([--enable-cpp7],
|
||||
[enable deprecated vips7 C++ binding (default: no)]),
|
||||
[enable_cpp7=$enableval
|
||||
],
|
||||
[enable_cpp7="no (default)"
|
||||
]
|
||||
)
|
||||
AM_CONDITIONAL(ENABLE_CPP7, [test x"$enable_cpp7" = x"yes"])
|
||||
|
||||
# optional supporting libraries
|
||||
|
||||
AC_ARG_WITH([gsf],
|
||||
@ -662,68 +685,6 @@ else
|
||||
with_magickpackage=none
|
||||
fi
|
||||
|
||||
if test x"$magick6" = x"yes"; then
|
||||
# we SetImageOption to disable some DICOM read processing, but that's only
|
||||
# in more recent imagemagicks and not in graphicsmagick
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$LIBS $MAGICK_LIBS"
|
||||
AC_CHECK_FUNCS(SetImageOption,
|
||||
AC_DEFINE(HAVE_SETIMAGEOPTION,1,[define if your magick has SetImageOption.])
|
||||
)
|
||||
LIBS="$save_LIBS"
|
||||
fi
|
||||
|
||||
if test x"$magick6" = x"yes"; then
|
||||
# newer ImageMagicks use MagickCoreGenesis instead of InitializeMagick argh
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$LIBS $MAGICK_LIBS"
|
||||
AC_CHECK_FUNCS(MagickCoreGenesis,
|
||||
AC_DEFINE(HAVE_MAGICKCOREGENESIS,1,
|
||||
[define if your magick has MagickCoreGenesis.]))
|
||||
LIBS="$save_LIBS"
|
||||
fi
|
||||
|
||||
if test x"$magick6" = x"yes"; then
|
||||
# newer ImageMagicks use ResetImagePropertyIterator instead of
|
||||
# ResetImageAttributeIterator argh
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$LIBS $MAGICK_LIBS"
|
||||
AC_CHECK_FUNCS(ResetImagePropertyIterator,
|
||||
AC_DEFINE(HAVE_RESETIMAGEPROPERTYITERATOR,1,
|
||||
[define if your magick has ResetImagePropertyIterator.]))
|
||||
LIBS="$save_LIBS"
|
||||
fi
|
||||
|
||||
if test x"$magick6" = x"yes"; then
|
||||
# so ... do we have ResetImageAttributeIterator()? GM does not
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$LIBS $MAGICK_LIBS"
|
||||
AC_CHECK_FUNCS(ResetImageAttributeIterator,
|
||||
AC_DEFINE(HAVE_RESETIMAGEATTRIBUTEITERATOR,1,
|
||||
[define if your magick has ResetImageAttributeIterator.]))
|
||||
LIBS="$save_LIBS"
|
||||
fi
|
||||
|
||||
if test x"$magick6" = x"yes"; then
|
||||
# GM does not have ResetImageProfileIterator
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$LIBS $MAGICK_LIBS"
|
||||
AC_CHECK_FUNCS(ResetImageProfileIterator,
|
||||
AC_DEFINE(HAVE_RESETIMAGEPROFILEITERATOR,1,
|
||||
[define if your magick has ResetImageProfileIterator.]))
|
||||
LIBS="$save_LIBS"
|
||||
fi
|
||||
|
||||
if test x"$magick6" = x"yes"; then
|
||||
# more recent magicks have GetVirtualPixels rather than GetImagePixels
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$LIBS $MAGICK_LIBS"
|
||||
AC_CHECK_FUNCS(GetVirtualPixels,
|
||||
AC_DEFINE(HAVE_GETVIRTUALPIXELS,1,
|
||||
[define if your magick has GetVirtualPixels.]))
|
||||
LIBS="$save_LIBS"
|
||||
fi
|
||||
|
||||
if test x"$magick6" = x"yes"; then
|
||||
# do we have number_scenes in image_info ... imagemagick uses this
|
||||
save_CFLAGS="$CFLAGS"
|
||||
@ -737,63 +698,51 @@ if test x"$magick6" = x"yes"; then
|
||||
fi
|
||||
|
||||
if test x"$magick6" = x"yes"; then
|
||||
# more recent magick6s have AcquireImage rather than AllocateImage argh
|
||||
# the magick6 API varies a lot between magick versions, and between GM and
|
||||
# IM
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$LIBS $MAGICK_LIBS"
|
||||
AC_CHECK_FUNCS(AcquireImage,
|
||||
AC_DEFINE(HAVE_ACQUIREIMAGE,1,
|
||||
[define if your magick has AcquireImage.]))
|
||||
AC_CHECK_FUNCS([InheritException AcquireExceptionInfo SetImageProperty SetImageExtent AcquireImage GetVirtualPixels ResetImageProfileIterator ResetImageAttributeIterator ResetImagePropertyIterator MagickCoreGenesis SetImageOption BlobToStringInfo OptimizePlusImageLayers OptimizeImageTransparency])
|
||||
LIBS="$save_LIBS"
|
||||
fi
|
||||
|
||||
if test x"$magick6" = x"yes"; then
|
||||
# more recent magick6s have SetImageExtent
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$LIBS $MAGICK_LIBS"
|
||||
AC_CHECK_FUNCS(SetImageExtent,
|
||||
AC_DEFINE(HAVE_SETIMAGEEXTENT,1,
|
||||
[define if your magick has SetImageExtent.]))
|
||||
LIBS="$save_LIBS"
|
||||
fi
|
||||
save_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $MAGICK_CFLAGS"
|
||||
|
||||
if test x"$magick6" = x"yes"; then
|
||||
# GM uses SetImageAttribute(), IM uses SetImageProperty()
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$LIBS $MAGICK_LIBS"
|
||||
AC_CHECK_FUNCS(SetImageProperty,
|
||||
AC_DEFINE(HAVE_SETIMAGEPROPERTY,1,
|
||||
[define if your magick has SetImageProperty.]))
|
||||
LIBS="$save_LIBS"
|
||||
fi
|
||||
# the range of ColorspaceType has expanded several times
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[#include <magick/api.h>],
|
||||
[ColorspaceType colorspace = CMYColorspace]
|
||||
)],
|
||||
[AC_DEFINE(HAVE_CMYCOLORSPACE,1,
|
||||
[define if your Magick has CMYColorspace.])
|
||||
]
|
||||
)
|
||||
|
||||
if test x"$magick6" = x"yes"; then
|
||||
# IM uses SetImageProfile() with StringInfo
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$LIBS $MAGICK_LIBS"
|
||||
AC_CHECK_FUNCS(BlobToStringInfo,
|
||||
AC_DEFINE(HAVE_BLOBTOSTRINGINFO,1,
|
||||
[define if your magick has BlobToStringInfo().]))
|
||||
LIBS="$save_LIBS"
|
||||
fi
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[#include <magick/api.h>],
|
||||
[ColorspaceType colorspace = HCLpColorspace]
|
||||
)],
|
||||
[AC_DEFINE(HAVE_HCLPCOLORSPACE,1,
|
||||
[define if your Magick has HCLpColorspace.])
|
||||
]
|
||||
)
|
||||
|
||||
if test x"$magick6" = x"yes"; then
|
||||
# GM is missing InheritException
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$LIBS $MAGICK_LIBS"
|
||||
AC_CHECK_FUNCS(InheritException,
|
||||
AC_DEFINE(HAVE_INHERITEXCEPTION,1,
|
||||
[define if your magick has InheritException.]))
|
||||
LIBS="$save_LIBS"
|
||||
fi
|
||||
# GetImageMagick() takes two args under GM, three under IM
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[#include <magick/api.h>],
|
||||
[(void)GetImageMagick(NULL, 0, NULL)]
|
||||
)],
|
||||
[AC_DEFINE(HAVE_GETIMAGEMAGICK3,1,
|
||||
[define if your GetImageMagick() takes three arguments.])
|
||||
]
|
||||
)
|
||||
|
||||
if test x"$magick6" = x"yes"; then
|
||||
# GM is missing AcquireExceptionInfo
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$LIBS $MAGICK_LIBS"
|
||||
AC_CHECK_FUNCS(AcquireExceptionInfo,
|
||||
AC_DEFINE(HAVE_ACQUIREEXCEPTIONINFO,1,
|
||||
[define if your magick has AcquireExceptionInfo.]))
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
fi
|
||||
|
||||
# have flags to turn load and save off independently ... some people will want
|
||||
@ -861,6 +810,19 @@ if test x"$with_orc" != x"no"; then
|
||||
)
|
||||
fi
|
||||
|
||||
# orc 0.4.30+ works with cf-protection, but 0.4.30 has a bug with multiple
|
||||
# definitions of OrcTargetPowerPCFlags, so insist on 0.4.31
|
||||
if test x"$with_orc" = x"yes"; then
|
||||
PKG_CHECK_MODULES(ORC_CF_PROTECTION, orc-0.4 >= 0.4.31,
|
||||
[AC_DEFINE(HAVE_ORC_CF_PROTECTION,1,
|
||||
[define if your orc works with cf-protection.]
|
||||
)
|
||||
],
|
||||
[:
|
||||
]
|
||||
)
|
||||
fi
|
||||
|
||||
# lcms ... refuse to use lcms1
|
||||
AC_ARG_WITH([lcms],
|
||||
AS_HELP_STRING([--without-lcms], [build without lcms (default: test)]))
|
||||
@ -1195,40 +1157,6 @@ if test x"$with_pangoft2" != x"no"; then
|
||||
)
|
||||
fi
|
||||
|
||||
# install vips8 python
|
||||
AC_ARG_ENABLE([pyvips8],
|
||||
AS_HELP_STRING([--enable-pyvips8],
|
||||
[install vips8 Python overrides (default: no)]),
|
||||
[enable_pyvips8=$enableval
|
||||
],
|
||||
[enable_pyvips8="no (default)"
|
||||
]
|
||||
)
|
||||
|
||||
if test x"$enable_pyvips8" = x"auto"; then
|
||||
PKG_CHECK_EXISTS([pygobject-3.0 >= 3.13.0],
|
||||
[enable_pyvips8=yes
|
||||
],
|
||||
[AC_MSG_WARN([pygobject-3.0 not found; disabling vips8 python support])
|
||||
enable_pyvips8=no
|
||||
]
|
||||
)
|
||||
fi
|
||||
|
||||
if test x"$enable_pyvips8" = x"yes"; then
|
||||
JD_PATH_PYTHON(2.7,,
|
||||
[enable_pyvips8=no
|
||||
AC_MSG_WARN([Python not found; disabling vips8 Python binding])
|
||||
]
|
||||
)
|
||||
fi
|
||||
|
||||
if test x"$enable_pyvips8" = x"yes"; then
|
||||
PKG_CHECK_MODULES(PYGOBJECT, [pygobject-3.0 >= 3.13.0])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(ENABLE_PYVIPS8, [test x"$enable_pyvips8" = x"yes"])
|
||||
|
||||
# look for TIFF with pkg-config ... fall back to our tester
|
||||
# pkgconfig support for libtiff starts with libtiff-4
|
||||
AC_ARG_WITH([tiff],
|
||||
@ -1250,6 +1178,20 @@ if test x"$with_tiff" != x"no"; then
|
||||
)
|
||||
fi
|
||||
|
||||
# WEBP in TIFF added in libtiff 4.0.10
|
||||
if test x"$with_tiff" != x"no"; then
|
||||
save_INCLUDES="$INCLUDES"
|
||||
INCLUDES="$INCLUDES $TIFF_INCLUDES"
|
||||
AC_CHECK_DECL(COMPRESSION_WEBP,[
|
||||
AC_DEFINE(HAVE_TIFF_COMPRESSION_WEBP,1,[define if your libtiff has webp.])
|
||||
],[
|
||||
],[
|
||||
[#include <tiffio.h>]
|
||||
]
|
||||
)
|
||||
INCLUDES="$save_INCLUDES"
|
||||
fi
|
||||
|
||||
# giflib
|
||||
FIND_GIFLIB(
|
||||
[with_giflib="yes (found by search)"
|
||||
@ -1374,6 +1316,13 @@ if test x"$with_libexif" != x"no"; then
|
||||
CPPFLAGS="$save_CPPFLAGS"
|
||||
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
|
||||
# sort includes to get longer, more specific dirs first
|
||||
# helps, for example, selecting graphicsmagick over imagemagick
|
||||
@ -1409,6 +1358,7 @@ AC_OUTPUT([
|
||||
libvips/Makefile
|
||||
libvips/arithmetic/Makefile
|
||||
libvips/colour/Makefile
|
||||
libvips/colour/profiles/Makefile
|
||||
libvips/conversion/Makefile
|
||||
libvips/convolution/Makefile
|
||||
libvips/deprecated/Makefile
|
||||
@ -1438,6 +1388,7 @@ AC_OUTPUT([
|
||||
doc/Makefile
|
||||
doc/libvips-docs.xml
|
||||
po/Makefile.in
|
||||
fuzz/Makefile
|
||||
])
|
||||
|
||||
AC_MSG_RESULT([dnl
|
||||
@ -1490,22 +1441,6 @@ image pyramid export: $with_gsf
|
||||
use libexif to load/save JPEG metadata: $with_libexif
|
||||
])
|
||||
|
||||
if test x"$found_introspection" = x"yes" -a "$VIPS_LIBDIR/girepository-1.0" != "$INTROSPECTION_TYPELIBDIR"; then
|
||||
case "$VIPS_LIBDIR" in
|
||||
/usr/local/Cellar/vips/*)
|
||||
;; # ignore for homebrew
|
||||
*)
|
||||
AC_MSG_RESULT([dnl
|
||||
Vips-8.0.typelib will be installed to $VIPS_LIBDIR/girepository-1.0, but
|
||||
your system repository seems to be $INTROSPECTION_TYPELIBDIR.
|
||||
You may need to add this directory to your typelib path, for example:
|
||||
|
||||
export GI_TYPELIB_PATH="$VIPS_LIBDIR/girepository-1.0"
|
||||
])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test x"$vips_os_win32" = x"yes"; then
|
||||
if test x"$have_g_win32_get_command_line" != x"yes"; then
|
||||
AC_MSG_RESULT([dnl
|
||||
|
@ -11,6 +11,7 @@ lib_LTLIBRARIES = libvips-cpp.la
|
||||
libvips_cpp_la_SOURCES = \
|
||||
VImage.cpp \
|
||||
VInterpolate.cpp \
|
||||
VStream.cpp \
|
||||
VError.cpp
|
||||
|
||||
libvips_cpp_la_LDFLAGS = \
|
||||
|
@ -169,7 +169,7 @@ VOption::set( const char *name, const char *value )
|
||||
|
||||
// input image
|
||||
VOption *
|
||||
VOption::set( const char *name, VImage value )
|
||||
VOption::set( const char *name, const VImage value )
|
||||
{
|
||||
Pair *pair = new Pair( name );
|
||||
|
||||
@ -592,7 +592,30 @@ VImage
|
||||
VImage::new_from_buffer( const std::string &buf, const char *option_string,
|
||||
VOption *options )
|
||||
{
|
||||
return( new_from_buffer( buf.c_str(), buf.size(), option_string, options ) );
|
||||
return( new_from_buffer( buf.c_str(), buf.size(),
|
||||
option_string, options ) );
|
||||
}
|
||||
|
||||
VImage
|
||||
VImage::new_from_stream( VStreamI streami, const char *option_string,
|
||||
VOption *options )
|
||||
{
|
||||
const char *operation_name;
|
||||
VImage out;
|
||||
|
||||
if( !(operation_name = vips_foreign_find_load_stream(
|
||||
streami.get_stream() )) ) {
|
||||
delete options;
|
||||
throw( VError() );
|
||||
}
|
||||
|
||||
options = (options ? options : VImage::option())->
|
||||
set( "streami", streami )->
|
||||
set( "out", &out );
|
||||
|
||||
call_option_string( operation_name, option_string, options );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage
|
||||
@ -679,6 +702,26 @@ VImage::write_to_buffer( const char *suffix, void **buf, size_t *size,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VImage::write_to_stream( const char *suffix, VStreamO streamo,
|
||||
VOption *options ) const
|
||||
{
|
||||
char filename[VIPS_PATH_MAX];
|
||||
char option_string[VIPS_PATH_MAX];
|
||||
const char *operation_name;
|
||||
|
||||
vips__filename_split8( suffix, filename, option_string );
|
||||
if( !(operation_name = vips_foreign_find_save_stream( filename )) ) {
|
||||
delete options;
|
||||
throw VError();
|
||||
}
|
||||
|
||||
call_option_string( operation_name, option_string,
|
||||
(options ? options : VImage::option())->
|
||||
set( "in", *this )->
|
||||
set( "streamo", streamo ) );
|
||||
}
|
||||
|
||||
#include "vips-operators.cpp"
|
||||
|
||||
std::vector<VImage>
|
||||
|
@ -61,7 +61,7 @@ VInterpolate::new_from_name( const char *name, VOption *options )
|
||||
}
|
||||
|
||||
VOption *
|
||||
VOption::set( const char *name, VInterpolate value )
|
||||
VOption::set( const char *name, const VInterpolate value )
|
||||
{
|
||||
Pair *pair = new Pair( name );
|
||||
|
||||
|
178
cplusplus/VStream.cpp
Normal file
178
cplusplus/VStream.cpp
Normal file
@ -0,0 +1,178 @@
|
||||
/* Object part of the VStreamI and VStreamO class
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Copyright (C) 1991-2001 The National Gallery
|
||||
|
||||
This program 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
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#include <vips/vips8>
|
||||
|
||||
#include <vips/debug.h>
|
||||
|
||||
/*
|
||||
#define VIPS_DEBUG
|
||||
#define VIPS_DEBUG_VERBOSE
|
||||
*/
|
||||
|
||||
VIPS_NAMESPACE_START
|
||||
|
||||
VStreamI
|
||||
VStreamI::new_from_descriptor( int descriptor )
|
||||
{
|
||||
VipsStreami *input;
|
||||
|
||||
if( !(input = vips_streami_new_from_descriptor( descriptor )) )
|
||||
throw VError();
|
||||
|
||||
VStreamI out( input );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VStreamI
|
||||
VStreamI::new_from_file( const char *filename )
|
||||
{
|
||||
VipsStreami *input;
|
||||
|
||||
if( !(input = vips_streami_new_from_file( filename )) )
|
||||
throw VError();
|
||||
|
||||
VStreamI out( input );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VStreamI
|
||||
VStreamI::new_from_blob( VipsBlob *blob )
|
||||
{
|
||||
VipsStreami *input;
|
||||
|
||||
if( !(input = vips_streami_new_from_blob( blob )) )
|
||||
throw VError();
|
||||
|
||||
VStreamI out( input );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VStreamI
|
||||
VStreamI::new_from_memory( const void *data,
|
||||
size_t size )
|
||||
{
|
||||
VipsStreami *input;
|
||||
|
||||
if( !(input = vips_streami_new_from_memory( data, size )) )
|
||||
throw VError();
|
||||
|
||||
VStreamI out( input );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VStreamI
|
||||
VStreamI::new_from_options( const char *options )
|
||||
{
|
||||
VipsStreami *input;
|
||||
|
||||
if( !(input = vips_streami_new_from_options( options )) )
|
||||
throw VError();
|
||||
|
||||
VStreamI out( input );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VOption *
|
||||
VOption::set( const char *name, const VStreamI value )
|
||||
{
|
||||
Pair *pair = new Pair( name );
|
||||
|
||||
pair->input = true;
|
||||
g_value_init( &pair->value, VIPS_TYPE_STREAMI );
|
||||
g_value_set_object( &pair->value, value.get_stream() );
|
||||
options.push_back( pair );
|
||||
|
||||
return( this );
|
||||
}
|
||||
|
||||
VStreamO
|
||||
VStreamO::new_to_descriptor( int descriptor )
|
||||
{
|
||||
VipsStreamo *output;
|
||||
|
||||
if( !(output = vips_streamo_new_to_descriptor( descriptor )) )
|
||||
throw VError();
|
||||
|
||||
VStreamO out( output );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VStreamO
|
||||
VStreamO::new_to_file( const char *filename )
|
||||
{
|
||||
VipsStreamo *output;
|
||||
|
||||
if( !(output = vips_streamo_new_to_file( filename )) )
|
||||
throw VError();
|
||||
|
||||
VStreamO out( output );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VStreamO
|
||||
VStreamO::new_to_memory()
|
||||
{
|
||||
VipsStreamo *output;
|
||||
|
||||
if( !(output = vips_streamo_new_to_memory()) )
|
||||
throw VError();
|
||||
|
||||
VStreamO out( output );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VOption *
|
||||
VOption::set( const char *name, const VStreamO value )
|
||||
{
|
||||
Pair *pair = new Pair( name );
|
||||
|
||||
pair->input = true;
|
||||
g_value_init( &pair->value, VIPS_TYPE_STREAMO );
|
||||
g_value_set_object( &pair->value, value.get_stream() );
|
||||
options.push_back( pair );
|
||||
|
||||
return( this );
|
||||
}
|
||||
|
||||
VIPS_NAMESPACE_END
|
@ -1,12 +1,8 @@
|
||||
/*
|
||||
* compile with:
|
||||
/* compile with:
|
||||
*
|
||||
* g++ -g -Wall resize.cpp `pkg-config vips-cpp --cflags --libs`
|
||||
*
|
||||
*/
|
||||
|
||||
#define DEBUG
|
||||
|
||||
#include <vips/vips8>
|
||||
|
||||
using namespace vips;
|
||||
@ -14,16 +10,15 @@ using namespace vips;
|
||||
int
|
||||
main( int argc, char **argv )
|
||||
{
|
||||
if( vips_init( argv[0] ) )
|
||||
if( VIPS_INIT( argv[0] ) )
|
||||
vips_error_exit( NULL );
|
||||
|
||||
VImage in = VImage::new_from_file( argv[1],
|
||||
VImage::option()->set( "access", VIPS_ACCESS_SEQUENTIAL ) );
|
||||
VInterpolate interp = VInterpolate::new_from_name( "nohalo" );
|
||||
VImage in = VImage::new_from_file( argv[1], VImage::option()
|
||||
->set( "access", "sequential" ) );
|
||||
|
||||
VImage out;
|
||||
|
||||
out = in.resize( 0.2, VImage::option()->set( "interpolate", interp ) );
|
||||
VImage out = in.resize( 0.2, VImage::option()
|
||||
->set( "kernel", "cubic" )
|
||||
->set( "vscale", 0.2 ) );
|
||||
|
||||
out.write_to_file( argv[2] );
|
||||
|
||||
|
@ -34,7 +34,8 @@ equal_vector( std::vector<double> a, std::vector<double> b )
|
||||
printf( "%g", a[i] );
|
||||
}
|
||||
printf( "], is [" );
|
||||
for( unsigned int i = 0; i < a.size(); i++ ) { if( i > 0 )
|
||||
for( unsigned int i = 0; i < a.size(); i++ ) {
|
||||
if( i > 0 )
|
||||
printf( ", " );
|
||||
printf( "%g", a[i] );
|
||||
}
|
||||
|
@ -25,9 +25,13 @@
|
||||
|
||||
import argparse
|
||||
|
||||
from pyvips import Operation, GValue, Error, \
|
||||
from pyvips import Introspect, Operation, GValue, Error, \
|
||||
ffi, gobject_lib, type_map, type_from_name, nickname_find, type_name
|
||||
|
||||
# TODO Move to pyvips.GValue
|
||||
stream_input_type = type_from_name('VipsStreami')
|
||||
stream_output_type = type_from_name('VipsStreamo')
|
||||
|
||||
# turn a GType into a C++ type
|
||||
gtype_to_cpp = {
|
||||
GValue.gbool_type: 'bool',
|
||||
@ -37,12 +41,17 @@ gtype_to_cpp = {
|
||||
GValue.refstr_type: 'char *',
|
||||
GValue.gflags_type: 'int',
|
||||
GValue.image_type: 'VImage',
|
||||
stream_input_type: 'VStreamI',
|
||||
stream_output_type: 'VStreamO',
|
||||
GValue.array_int_type: 'std::vector<int>',
|
||||
GValue.array_double_type: 'std::vector<double>',
|
||||
GValue.array_image_type: 'std::vector<VImage>',
|
||||
GValue.blob_type: 'VipsBlob *'
|
||||
}
|
||||
|
||||
cplusplus_suffixes = ('*', '&')
|
||||
cplusplus_keywords = ('case', 'switch')
|
||||
|
||||
# values for VipsArgumentFlags
|
||||
_REQUIRED = 1
|
||||
_INPUT = 16
|
||||
@ -78,67 +87,43 @@ def cppize(name):
|
||||
|
||||
|
||||
def generate_operation(operation_name, declaration_only=False):
|
||||
op = Operation.new_from_name(operation_name)
|
||||
intro = Introspect.get(operation_name)
|
||||
|
||||
# we are only interested in non-deprecated args
|
||||
args = [[name, flags] for name, flags in op.get_args()
|
||||
if not flags & _DEPRECATED]
|
||||
|
||||
# find the first required input image arg, if any ... that will be self
|
||||
member_x = None
|
||||
for name, flags in args:
|
||||
if ((flags & _INPUT) != 0 and
|
||||
(flags & _REQUIRED) != 0 and
|
||||
op.get_typeof(name) == GValue.image_type):
|
||||
member_x = name
|
||||
break
|
||||
|
||||
required_input = [name for name, flags in args
|
||||
if (flags & _INPUT) != 0 and
|
||||
(flags & _REQUIRED) != 0 and
|
||||
name != member_x]
|
||||
|
||||
required_output = [name for name, flags in args
|
||||
if ((flags & _OUTPUT) != 0 and
|
||||
(flags & _REQUIRED) != 0) or
|
||||
((flags & _INPUT) != 0 and
|
||||
(flags & _REQUIRED) != 0 and
|
||||
(flags & _MODIFY) != 0) and
|
||||
name != member_x]
|
||||
required_output = [name for name in intro.required_output if name != intro.member_x]
|
||||
|
||||
has_output = len(required_output) >= 1
|
||||
|
||||
# Add a C++ style comment block with some additional markings (@param,
|
||||
# Add a C++ style comment block with some additional markings (@param,
|
||||
# @return)
|
||||
if declaration_only:
|
||||
result = '\n/**\n * {}.'.format(op.get_description().capitalize())
|
||||
result = '\n/**\n * {}.'.format(intro.description.capitalize())
|
||||
|
||||
for name in required_input:
|
||||
for name in intro.method_args:
|
||||
result += '\n * @param {} {}.' \
|
||||
.format(cppize(name), op.get_blurb(name))
|
||||
.format(cppize(name), intro.details[name]['blurb'])
|
||||
|
||||
if has_output:
|
||||
# skip the first element
|
||||
for name in required_output[1:]:
|
||||
result += '\n * @param {} {}.' \
|
||||
.format(cppize(name), op.get_blurb(name))
|
||||
.format(cppize(name), intro.details[name]['blurb'])
|
||||
|
||||
result += '\n * @param options Optional options.'
|
||||
|
||||
if has_output:
|
||||
result += '\n * @return {}.' \
|
||||
.format(op.get_blurb(required_output[0]))
|
||||
.format(intro.details[required_output[0]]['blurb'])
|
||||
|
||||
result += '\n */\n'
|
||||
else:
|
||||
result = '\n'
|
||||
|
||||
if member_x is None and declaration_only:
|
||||
if intro.member_x is None and declaration_only:
|
||||
result += 'static '
|
||||
if has_output:
|
||||
# the first output arg will be used as the result
|
||||
cpp_type = get_cpp_type(op.get_typeof(required_output[0]))
|
||||
spacing = '' if cpp_type.endswith('*') else ' '
|
||||
cpp_type = get_cpp_type(intro.details[required_output[0]]['type'])
|
||||
spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' '
|
||||
result += '{0}{1}'.format(cpp_type, spacing)
|
||||
else:
|
||||
result += 'void '
|
||||
@ -146,26 +131,32 @@ def generate_operation(operation_name, declaration_only=False):
|
||||
if not declaration_only:
|
||||
result += 'VImage::'
|
||||
|
||||
result += '{0}( '.format(operation_name)
|
||||
for name in required_input:
|
||||
gtype = op.get_typeof(name)
|
||||
cplusplus_operation = operation_name
|
||||
if operation_name in cplusplus_keywords:
|
||||
cplusplus_operation += '_image'
|
||||
|
||||
result += '{0}( '.format(cplusplus_operation)
|
||||
for name in intro.method_args:
|
||||
details = intro.details[name]
|
||||
gtype = details['type']
|
||||
cpp_type = get_cpp_type(gtype)
|
||||
spacing = '' if cpp_type.endswith('*') else ' '
|
||||
spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' '
|
||||
result += '{0}{1}{2}, '.format(cpp_type, spacing, cppize(name))
|
||||
|
||||
# output params are passed by reference
|
||||
if has_output:
|
||||
# skip the first element
|
||||
for name in required_output[1:]:
|
||||
gtype = op.get_typeof(name)
|
||||
details = intro.details[name]
|
||||
gtype = details['type']
|
||||
cpp_type = get_cpp_type(gtype)
|
||||
spacing = '' if cpp_type.endswith('*') else ' '
|
||||
spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' '
|
||||
result += '{0}{1}*{2}, '.format(cpp_type, spacing, cppize(name))
|
||||
|
||||
result += 'VOption *options {0})'.format('= 0 ' if declaration_only else '')
|
||||
|
||||
# if no 'this' available, it's a class method and they are all const
|
||||
if member_x is not None:
|
||||
if intro.member_x is not None:
|
||||
result += ' const'
|
||||
|
||||
if declaration_only:
|
||||
@ -178,17 +169,17 @@ def generate_operation(operation_name, declaration_only=False):
|
||||
if has_output:
|
||||
# the first output arg will be used as the result
|
||||
name = required_output[0]
|
||||
cpp_type = get_cpp_type(op.get_typeof(name))
|
||||
spacing = '' if cpp_type.endswith('*') else ' '
|
||||
cpp_type = get_cpp_type(intro.details[name]['type'])
|
||||
spacing = '' if cpp_type.endswith(cplusplus_suffixes) else ' '
|
||||
result += ' {0}{1}{2};\n\n'.format(cpp_type, spacing, cppize(name))
|
||||
|
||||
result += ' call( "{0}",\n'.format(operation_name)
|
||||
result += ' (options ? options : VImage::option())'
|
||||
if member_x is not None:
|
||||
if intro.member_x is not None:
|
||||
result += '->\n'
|
||||
result += ' set( "{0}", *this )'.format(member_x)
|
||||
result += ' set( "{0}", *this )'.format(intro.member_x)
|
||||
|
||||
all_required = required_input
|
||||
all_required = intro.method_args
|
||||
|
||||
if has_output:
|
||||
# first element needs to be passed by reference
|
||||
@ -223,10 +214,10 @@ def generate_operators(declarations_only=False):
|
||||
nickname = nickname_find(gtype)
|
||||
try:
|
||||
# can fail for abstract types
|
||||
op = Operation.new_from_name(nickname)
|
||||
intro = Introspect.get(nickname)
|
||||
|
||||
# we are only interested in non-deprecated operations
|
||||
if (op.get_flags() & _OPERATION_DEPRECATED) == 0:
|
||||
if (intro.flags & _OPERATION_DEPRECATED) == 0:
|
||||
all_nicknames.append(nickname)
|
||||
except Error:
|
||||
pass
|
||||
|
@ -2,6 +2,7 @@ pkginclude_HEADERS = \
|
||||
VError8.h \
|
||||
VImage8.h \
|
||||
VInterpolate8.h \
|
||||
VStream8.h \
|
||||
vips8 \
|
||||
vips-operators.h
|
||||
|
||||
|
@ -169,6 +169,8 @@ public:
|
||||
|
||||
class VIPS_CPLUSPLUS_API VImage;
|
||||
class VIPS_CPLUSPLUS_API VInterpolate;
|
||||
class VIPS_CPLUSPLUS_API VStreamI;
|
||||
class VIPS_CPLUSPLUS_API VStreamO;
|
||||
class VIPS_CPLUSPLUS_API VOption;
|
||||
|
||||
class VOption
|
||||
@ -220,8 +222,10 @@ public:
|
||||
VOption *set( const char *name, int value );
|
||||
VOption *set( const char *name, double value );
|
||||
VOption *set( const char *name, const char *value );
|
||||
VOption *set( const char *name, VImage value );
|
||||
VOption *set( const char *name, VInterpolate value );
|
||||
VOption *set( const char *name, const VImage value );
|
||||
VOption *set( const char *name, const VInterpolate value );
|
||||
VOption *set( const char *name, const VStreamI value );
|
||||
VOption *set( const char *name, const VStreamO value );
|
||||
VOption *set( const char *name, std::vector<VImage> value );
|
||||
VOption *set( const char *name, std::vector<double> value );
|
||||
VOption *set( const char *name, std::vector<int> value );
|
||||
@ -357,6 +361,13 @@ public:
|
||||
vips_image_set_array_int( this->get_image(), field, value, n );
|
||||
}
|
||||
|
||||
void
|
||||
set( const char *field, std::vector<int> value )
|
||||
{
|
||||
vips_image_set_array_int( this->get_image(), field, &value[0],
|
||||
static_cast<int>( value.size() ) );
|
||||
}
|
||||
|
||||
void
|
||||
set( const char *field, double value )
|
||||
{
|
||||
@ -401,6 +412,20 @@ public:
|
||||
throw( VError() );
|
||||
}
|
||||
|
||||
std::vector<int>
|
||||
get_array_int( const char *field ) const
|
||||
{
|
||||
int length;
|
||||
int *array;
|
||||
|
||||
if( vips_image_get_array_int( this->get_image(), field, &array, &length ) )
|
||||
throw( VError() );
|
||||
|
||||
std::vector<int> vector( array, array + length );
|
||||
|
||||
return( vector );
|
||||
}
|
||||
|
||||
double
|
||||
get_double( const char *field ) const
|
||||
{
|
||||
@ -489,6 +514,9 @@ public:
|
||||
static VImage new_from_buffer( const std::string &buf,
|
||||
const char *option_string, VOption *options = 0 );
|
||||
|
||||
static VImage new_from_stream( VStreamI streami,
|
||||
const char *option_string, VOption *options = 0 );
|
||||
|
||||
static VImage new_matrix( int width, int height );
|
||||
|
||||
static VImage
|
||||
@ -541,6 +569,9 @@ public:
|
||||
void write_to_buffer( const char *suffix, void **buf, size_t *size,
|
||||
VOption *options = 0 ) const;
|
||||
|
||||
void write_to_stream( const char *suffix, VStreamO streamo,
|
||||
VOption *options = 0 ) const;
|
||||
|
||||
void *
|
||||
write_to_memory( size_t *size ) const
|
||||
{
|
||||
|
@ -30,12 +30,6 @@
|
||||
#ifndef VIPS_VINTERPOLATE_H
|
||||
#define VIPS_VINTERPOLATE_H
|
||||
|
||||
#include <list>
|
||||
#include <complex>
|
||||
#include <vector>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <vips/vips.h>
|
||||
|
||||
VIPS_NAMESPACE_START
|
||||
@ -61,4 +55,4 @@ public:
|
||||
|
||||
VIPS_NAMESPACE_END
|
||||
|
||||
#endif /*VIPS_VIMAGE_H*/
|
||||
#endif /*VIPS_VINTERPOLATE_H*/
|
||||
|
96
cplusplus/include/vips/VStream8.h
Normal file
96
cplusplus/include/vips/VStream8.h
Normal file
@ -0,0 +1,96 @@
|
||||
// VIPS stream input/output wrapper
|
||||
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
#ifndef VIPS_VSTREAM_H
|
||||
#define VIPS_VSTREAM_H
|
||||
|
||||
#include <vips/vips.h>
|
||||
|
||||
VIPS_NAMESPACE_START
|
||||
|
||||
class VStreamI : VObject
|
||||
{
|
||||
public:
|
||||
VStreamI( VipsStreami *input, VSteal steal = STEAL ) :
|
||||
VObject( (VipsObject *) input, steal )
|
||||
{
|
||||
}
|
||||
|
||||
static
|
||||
VStreamI new_from_descriptor( int descriptor );
|
||||
|
||||
static
|
||||
VStreamI new_from_file( const char *filename );
|
||||
|
||||
static
|
||||
VStreamI new_from_blob( VipsBlob *blob );
|
||||
|
||||
static
|
||||
VStreamI new_from_memory( const void *data,
|
||||
size_t size );
|
||||
|
||||
static
|
||||
VStreamI new_from_options( const char *options );
|
||||
|
||||
VipsStreami *
|
||||
get_stream() const
|
||||
{
|
||||
return( (VipsStreami *) VObject::get_object() );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class VStreamO : VObject
|
||||
{
|
||||
public:
|
||||
VStreamO( VipsStreamo *output, VSteal steal = STEAL ) :
|
||||
VObject( (VipsObject *) output, steal )
|
||||
{
|
||||
}
|
||||
|
||||
static
|
||||
VStreamO new_to_descriptor( int descriptor );
|
||||
|
||||
static
|
||||
VStreamO new_to_file( const char *filename );
|
||||
|
||||
static
|
||||
VStreamO new_to_memory();
|
||||
|
||||
VipsStreamo *
|
||||
get_stream() const
|
||||
{
|
||||
return( (VipsStreamo *) VObject::get_object() );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
VIPS_NAMESPACE_END
|
||||
|
||||
#endif /*VIPS_VSTREAM_H*/
|
@ -1,5 +1,5 @@
|
||||
// headers for vips operations
|
||||
// Wed Apr 24 15:50:21 CEST 2019
|
||||
// Fri 29 Nov 2019 02:46:41 PM CET
|
||||
// this file is generated automatically, do not edit!
|
||||
|
||||
/**
|
||||
@ -296,6 +296,14 @@ VImage cache( VOption *options = 0 ) const;
|
||||
*/
|
||||
VImage canny( VOption *options = 0 ) const;
|
||||
|
||||
/**
|
||||
* Use pixel values to pick cases from an array of images.
|
||||
* @param cases Array of case images.
|
||||
* @param options Optional options.
|
||||
* @return Output image.
|
||||
*/
|
||||
VImage case_image( std::vector<VImage> cases, VOption *options = 0 ) const;
|
||||
|
||||
/**
|
||||
* Cast an image.
|
||||
* @param format Format to cast to.
|
||||
@ -1029,6 +1037,14 @@ static VImage jpegload( const char *filename, VOption *options = 0 );
|
||||
*/
|
||||
static VImage jpegload_buffer( VipsBlob *buffer, VOption *options = 0 );
|
||||
|
||||
/**
|
||||
* Load image from jpeg stream.
|
||||
* @param streami Stream to load from.
|
||||
* @param options Optional options.
|
||||
* @return Output image.
|
||||
*/
|
||||
static VImage jpegload_stream( VStreamI streami, VOption *options = 0 );
|
||||
|
||||
/**
|
||||
* Save image to jpeg file.
|
||||
* @param filename Filename to save to.
|
||||
@ -1049,6 +1065,13 @@ VipsBlob *jpegsave_buffer( VOption *options = 0 ) const;
|
||||
*/
|
||||
void jpegsave_mime( VOption *options = 0 ) const;
|
||||
|
||||
/**
|
||||
* Save image to jpeg stream.
|
||||
* @param streamo Stream to save to.
|
||||
* @param options Optional options.
|
||||
*/
|
||||
void jpegsave_stream( VStreamO streamo, VOption *options = 0 ) const;
|
||||
|
||||
/**
|
||||
* Label regions in an image.
|
||||
* @param options Optional options.
|
||||
@ -1112,7 +1135,7 @@ void magicksave( const char *filename, VOption *options = 0 ) const;
|
||||
VipsBlob *magicksave_buffer( VOption *options = 0 ) const;
|
||||
|
||||
/**
|
||||
* Resample with an mapim image.
|
||||
* Resample with a map image.
|
||||
* @param index Index pixels with this.
|
||||
* @param options Optional options.
|
||||
* @return Output image.
|
||||
@ -1492,6 +1515,14 @@ static VImage pngload( const char *filename, VOption *options = 0 );
|
||||
*/
|
||||
static VImage pngload_buffer( VipsBlob *buffer, VOption *options = 0 );
|
||||
|
||||
/**
|
||||
* Load png from stream.
|
||||
* @param streami Stream to load from.
|
||||
* @param options Optional options.
|
||||
* @return Output image.
|
||||
*/
|
||||
static VImage pngload_stream( VStreamI streami, VOption *options = 0 );
|
||||
|
||||
/**
|
||||
* Save image to png file.
|
||||
* @param filename Filename to save to.
|
||||
@ -1506,6 +1537,13 @@ void pngsave( const char *filename, VOption *options = 0 ) const;
|
||||
*/
|
||||
VipsBlob *pngsave_buffer( VOption *options = 0 ) const;
|
||||
|
||||
/**
|
||||
* Save image to png stream.
|
||||
* @param streamo Stream to save to.
|
||||
* @param options Optional options.
|
||||
*/
|
||||
void pngsave_stream( VStreamO streamo, VOption *options = 0 ) const;
|
||||
|
||||
/**
|
||||
* Load ppm from file.
|
||||
* @param filename Filename to load from.
|
||||
@ -1575,6 +1613,22 @@ VImage rad2float( VOption *options = 0 ) const;
|
||||
*/
|
||||
static VImage radload( const char *filename, VOption *options = 0 );
|
||||
|
||||
/**
|
||||
* Load rad from buffer.
|
||||
* @param buffer Buffer to load from.
|
||||
* @param options Optional options.
|
||||
* @return Output image.
|
||||
*/
|
||||
static VImage radload_buffer( VipsBlob *buffer, VOption *options = 0 );
|
||||
|
||||
/**
|
||||
* Load rad from stream.
|
||||
* @param streami Stream to load from.
|
||||
* @param options Optional options.
|
||||
* @return Output image.
|
||||
*/
|
||||
static VImage radload_stream( VStreamI streami, VOption *options = 0 );
|
||||
|
||||
/**
|
||||
* Save image to radiance file.
|
||||
* @param filename Filename to save to.
|
||||
@ -1589,6 +1643,13 @@ void radsave( const char *filename, VOption *options = 0 ) const;
|
||||
*/
|
||||
VipsBlob *radsave_buffer( VOption *options = 0 ) const;
|
||||
|
||||
/**
|
||||
* Save image to radiance stream.
|
||||
* @param streamo Stream to save to.
|
||||
* @param options Optional options.
|
||||
*/
|
||||
void radsave_stream( VStreamO streamo, VOption *options = 0 ) const;
|
||||
|
||||
/**
|
||||
* Rank filter.
|
||||
* @param width Window width in pixels.
|
||||
@ -1931,6 +1992,22 @@ static VImage svgload( const char *filename, VOption *options = 0 );
|
||||
*/
|
||||
static VImage svgload_buffer( VipsBlob *buffer, VOption *options = 0 );
|
||||
|
||||
/**
|
||||
* Load svg from stream.
|
||||
* @param streami Stream to load from.
|
||||
* @param options Optional options.
|
||||
* @return Output image.
|
||||
*/
|
||||
static VImage svgload_stream( VStreamI streami, VOption *options = 0 );
|
||||
|
||||
/**
|
||||
* Find the index of the first non-zero pixel in tests.
|
||||
* @param tests Table of images to test.
|
||||
* @param options Optional options.
|
||||
* @return Output image.
|
||||
*/
|
||||
static VImage switch_image( std::vector<VImage> tests, VOption *options = 0 );
|
||||
|
||||
/**
|
||||
* Run an external command.
|
||||
* @param cmd_format Command to run.
|
||||
@ -1972,6 +2049,15 @@ static VImage thumbnail_buffer( VipsBlob *buffer, int width, VOption *options =
|
||||
*/
|
||||
VImage thumbnail_image( int width, VOption *options = 0 ) const;
|
||||
|
||||
/**
|
||||
* Generate thumbnail from stream.
|
||||
* @param streami Stream to load from.
|
||||
* @param width Size to this width.
|
||||
* @param options Optional options.
|
||||
* @return Output image.
|
||||
*/
|
||||
static VImage thumbnail_stream( VStreamI streami, int width, VOption *options = 0 );
|
||||
|
||||
/**
|
||||
* Load tiff from file.
|
||||
* @param filename Filename to load from.
|
||||
@ -1988,6 +2074,14 @@ static VImage tiffload( const char *filename, VOption *options = 0 );
|
||||
*/
|
||||
static VImage tiffload_buffer( VipsBlob *buffer, VOption *options = 0 );
|
||||
|
||||
/**
|
||||
* Load tiff from stream.
|
||||
* @param streami Stream to load from.
|
||||
* @param options Optional options.
|
||||
* @return Output image.
|
||||
*/
|
||||
static VImage tiffload_stream( VStreamI streami, VOption *options = 0 );
|
||||
|
||||
/**
|
||||
* Save image to tiff file.
|
||||
* @param filename Filename to save to.
|
||||
@ -2061,6 +2155,14 @@ static VImage webpload( const char *filename, VOption *options = 0 );
|
||||
*/
|
||||
static VImage webpload_buffer( VipsBlob *buffer, VOption *options = 0 );
|
||||
|
||||
/**
|
||||
* Load webp from stream.
|
||||
* @param streami Stream to load from.
|
||||
* @param options Optional options.
|
||||
* @return Output image.
|
||||
*/
|
||||
static VImage webpload_stream( VStreamI streami, VOption *options = 0 );
|
||||
|
||||
/**
|
||||
* Save image to webp file.
|
||||
* @param filename Filename to save to.
|
||||
@ -2075,6 +2177,13 @@ void webpsave( const char *filename, VOption *options = 0 ) const;
|
||||
*/
|
||||
VipsBlob *webpsave_buffer( VOption *options = 0 ) const;
|
||||
|
||||
/**
|
||||
* Save image to webp stream.
|
||||
* @param streamo Stream to save to.
|
||||
* @param options Optional options.
|
||||
*/
|
||||
void webpsave_stream( VStreamO streamo, VOption *options = 0 ) const;
|
||||
|
||||
/**
|
||||
* Make a worley noise image.
|
||||
* @param width Image width in pixels.
|
||||
|
@ -52,5 +52,6 @@
|
||||
#include "VError8.h"
|
||||
#include "VImage8.h"
|
||||
#include "VInterpolate8.h"
|
||||
#include "VStream8.h"
|
||||
|
||||
#endif /*VIPS_CPLUSPLUS*/
|
||||
|
@ -1,5 +1,5 @@
|
||||
// bodies for vips operations
|
||||
// Wed Apr 24 15:50:21 CEST 2019
|
||||
// Fri 29 Nov 2019 02:46:41 PM CET
|
||||
// this file is generated automatically, do not edit!
|
||||
|
||||
VImage VImage::CMC2LCh( VOption *options ) const
|
||||
@ -491,6 +491,19 @@ VImage VImage::canny( VOption *options ) const
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::case_image( std::vector<VImage> cases, VOption *options ) const
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "case",
|
||||
(options ? options : VImage::option())->
|
||||
set( "index", *this )->
|
||||
set( "out", &out )->
|
||||
set( "cases", cases ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::cast( VipsBandFormat format, VOption *options ) const
|
||||
{
|
||||
VImage out;
|
||||
@ -1615,6 +1628,18 @@ VImage VImage::jpegload_buffer( VipsBlob *buffer, VOption *options )
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::jpegload_stream( VStreamI streami, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "jpegload_stream",
|
||||
(options ? options : VImage::option())->
|
||||
set( "out", &out )->
|
||||
set( "streami", streami ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
void VImage::jpegsave( const char *filename, VOption *options ) const
|
||||
{
|
||||
call( "jpegsave",
|
||||
@ -1642,6 +1667,14 @@ void VImage::jpegsave_mime( VOption *options ) const
|
||||
set( "in", *this ) );
|
||||
}
|
||||
|
||||
void VImage::jpegsave_stream( VStreamO streamo, VOption *options ) const
|
||||
{
|
||||
call( "jpegsave_stream",
|
||||
(options ? options : VImage::option())->
|
||||
set( "in", *this )->
|
||||
set( "streamo", streamo ) );
|
||||
}
|
||||
|
||||
VImage VImage::labelregions( VOption *options ) const
|
||||
{
|
||||
VImage mask;
|
||||
@ -2286,6 +2319,18 @@ VImage VImage::pngload_buffer( VipsBlob *buffer, VOption *options )
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::pngload_stream( VStreamI streami, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "pngload_stream",
|
||||
(options ? options : VImage::option())->
|
||||
set( "out", &out )->
|
||||
set( "streami", streami ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
void VImage::pngsave( const char *filename, VOption *options ) const
|
||||
{
|
||||
call( "pngsave",
|
||||
@ -2306,6 +2351,14 @@ VipsBlob *VImage::pngsave_buffer( VOption *options ) const
|
||||
return( buffer );
|
||||
}
|
||||
|
||||
void VImage::pngsave_stream( VStreamO streamo, VOption *options ) const
|
||||
{
|
||||
call( "pngsave_stream",
|
||||
(options ? options : VImage::option())->
|
||||
set( "in", *this )->
|
||||
set( "streamo", streamo ) );
|
||||
}
|
||||
|
||||
VImage VImage::ppmload( const char *filename, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
@ -2413,6 +2466,30 @@ VImage VImage::radload( const char *filename, VOption *options )
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::radload_buffer( VipsBlob *buffer, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "radload_buffer",
|
||||
(options ? options : VImage::option())->
|
||||
set( "out", &out )->
|
||||
set( "buffer", buffer ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::radload_stream( VStreamI streami, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "radload_stream",
|
||||
(options ? options : VImage::option())->
|
||||
set( "out", &out )->
|
||||
set( "streami", streami ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
void VImage::radsave( const char *filename, VOption *options ) const
|
||||
{
|
||||
call( "radsave",
|
||||
@ -2433,6 +2510,14 @@ VipsBlob *VImage::radsave_buffer( VOption *options ) const
|
||||
return( buffer );
|
||||
}
|
||||
|
||||
void VImage::radsave_stream( VStreamO streamo, VOption *options ) const
|
||||
{
|
||||
call( "radsave_stream",
|
||||
(options ? options : VImage::option())->
|
||||
set( "in", *this )->
|
||||
set( "streamo", streamo ) );
|
||||
}
|
||||
|
||||
VImage VImage::rank( int width, int height, int index, VOption *options ) const
|
||||
{
|
||||
VImage out;
|
||||
@ -2977,6 +3062,30 @@ VImage VImage::svgload_buffer( VipsBlob *buffer, VOption *options )
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::svgload_stream( VStreamI streami, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "svgload_stream",
|
||||
(options ? options : VImage::option())->
|
||||
set( "out", &out )->
|
||||
set( "streami", streami ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::switch_image( std::vector<VImage> tests, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "switch",
|
||||
(options ? options : VImage::option())->
|
||||
set( "out", &out )->
|
||||
set( "tests", tests ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
void VImage::system( const char *cmd_format, VOption *options )
|
||||
{
|
||||
call( "system",
|
||||
@ -3035,6 +3144,19 @@ VImage VImage::thumbnail_image( int width, VOption *options ) const
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::thumbnail_stream( VStreamI streami, int width, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "thumbnail_stream",
|
||||
(options ? options : VImage::option())->
|
||||
set( "out", &out )->
|
||||
set( "streami", streami )->
|
||||
set( "width", width ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::tiffload( const char *filename, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
@ -3059,6 +3181,18 @@ VImage VImage::tiffload_buffer( VipsBlob *buffer, VOption *options )
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::tiffload_stream( VStreamI streami, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "tiffload_stream",
|
||||
(options ? options : VImage::option())->
|
||||
set( "out", &out )->
|
||||
set( "streami", streami ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
void VImage::tiffsave( const char *filename, VOption *options ) const
|
||||
{
|
||||
call( "tiffsave",
|
||||
@ -3170,6 +3304,18 @@ VImage VImage::webpload_buffer( VipsBlob *buffer, VOption *options )
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::webpload_stream( VStreamI streami, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "webpload_stream",
|
||||
(options ? options : VImage::option())->
|
||||
set( "out", &out )->
|
||||
set( "streami", streami ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
void VImage::webpsave( const char *filename, VOption *options ) const
|
||||
{
|
||||
call( "webpsave",
|
||||
@ -3190,6 +3336,14 @@ VipsBlob *VImage::webpsave_buffer( VOption *options ) const
|
||||
return( buffer );
|
||||
}
|
||||
|
||||
void VImage::webpsave_stream( VStreamO streamo, VOption *options ) const
|
||||
{
|
||||
call( "webpsave_stream",
|
||||
(options ? options : VImage::option())->
|
||||
set( "in", *this )->
|
||||
set( "streamo", streamo ) );
|
||||
}
|
||||
|
||||
VImage VImage::worley( int width, int height, VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
@ -80,7 +80,7 @@ main( int argc, char **argv )
|
||||
|
||||
/* Call the operation. This will look up the operation+args in the vips
|
||||
* operation cache and either return a previous operation, or build
|
||||
* this one. In either case, we have a new ref we mst release.
|
||||
* this one. In either case, we have a new ref we must release.
|
||||
*/
|
||||
if( !(new_op = vips_cache_operation_build( op )) ) {
|
||||
g_object_unref( op );
|
||||
@ -114,7 +114,7 @@ main( int argc, char **argv )
|
||||
```
|
||||
|
||||
libvips has a couple of extra things to let you examine the arguments and
|
||||
types of an operator at runtime. Use vips_lib.vips_argument_map() to loop
|
||||
types of an operator at runtime. Use vips_argument_map() to loop
|
||||
over all the arguments of an operator, and vips_object_get_argument()
|
||||
to fetch the type and flags of a specific argument.
|
||||
|
||||
@ -151,7 +151,7 @@ operator overloads, and various other useful features.
|
||||
|
||||
# Dynamic language with FFI
|
||||
|
||||
Languages like Ruby, Python, JavaScript and Lua can't call C directly, but
|
||||
Languages like Ruby, Python, JavaScript and LuaJIT can't call C directly, but
|
||||
they do support FFI. The bindings for these languages work rather like C++,
|
||||
but use FFI to call into libvips and run operations.
|
||||
|
||||
@ -216,4 +216,4 @@ $ yelp-build html .
|
||||
```
|
||||
|
||||
To make HTML docs. This is an easy way to see what you can call in the
|
||||
library.
|
||||
library.
|
||||
|
@ -16,7 +16,7 @@
|
||||
<para>
|
||||
This chapter runs through the four main styles that have been found to work well. If you want to write a new binding, one of these should be close to what you need.
|
||||
</para>
|
||||
<refsect3 id="dont-bind-the-top-level-c-api">
|
||||
<section xml:id="dont-bind-the-top-level-c-api">
|
||||
<title>Don’t bind the top-level C API</title>
|
||||
<para>
|
||||
The libvips C API (vips_add() and so on) is very inconvenient and dangerous to use from other languages due to its heavy use of varargs.
|
||||
@ -79,7 +79,7 @@ main( int argc, char **argv )
|
||||
|
||||
/* Call the operation. This will look up the operation+args in the vips
|
||||
* operation cache and either return a previous operation, or build
|
||||
* this one. In either case, we have a new ref we mst release.
|
||||
* this one. In either case, we have a new ref we must release.
|
||||
*/
|
||||
if( !(new_op = vips_cache_operation_build( op )) ) {
|
||||
g_object_unref( op );
|
||||
@ -112,13 +112,13 @@ main( int argc, char **argv )
|
||||
}
|
||||
</programlisting>
|
||||
<para>
|
||||
libvips has a couple of extra things to let you examine the arguments and types of an operator at runtime. Use vips_lib.vips_argument_map() to loop over all the arguments of an operator, and vips_object_get_argument() to fetch the type and flags of a specific argument.
|
||||
libvips has a couple of extra things to let you examine the arguments and types of an operator at runtime. Use vips_argument_map() to loop over all the arguments of an operator, and vips_object_get_argument() to fetch the type and flags of a specific argument.
|
||||
</para>
|
||||
<para>
|
||||
Use vips_operation_get_flags() to get general information about an operator.
|
||||
</para>
|
||||
</refsect3>
|
||||
<refsect3 id="compiled-language-which-can-call-c">
|
||||
</section>
|
||||
<section xml:id="compiled-language-which-can-call-c">
|
||||
<title>Compiled language which can call C</title>
|
||||
<para>
|
||||
The C++ binding uses this lower layer to define a function called <literal>VImage::call()</literal> which can call any libvips operator with a not-varargs set of variable arguments.
|
||||
@ -144,23 +144,23 @@ VImage VImage::invert( VOption *options )
|
||||
<para>
|
||||
The <literal>VImage</literal> class also adds automatic reference counting, constant expansion, operator overloads, and various other useful features.
|
||||
</para>
|
||||
</refsect3>
|
||||
<refsect3 id="dynamic-language-with-ffi">
|
||||
</section>
|
||||
<section xml:id="dynamic-language-with-ffi">
|
||||
<title>Dynamic language with FFI</title>
|
||||
<para>
|
||||
Languages like Ruby, Python, JavaScript and Lua can’t call C directly, but they do support FFI. The bindings for these languages work rather like C++, but use FFI to call into libvips and run operations.
|
||||
Languages like Ruby, Python, JavaScript and LuaJIT can’t call C directly, but they do support FFI. The bindings for these languages work rather like C++, but use FFI to call into libvips and run operations.
|
||||
</para>
|
||||
<para>
|
||||
Since these languages are dynamic, they can add another trick: they intercept the method-missing hook and attempt to run any method calls not implemented by the <literal>Image</literal> class as libvips operators. This makes these bindings self-writing: they only contain a small amount of code and just expose everything they find in the libvips class hierarchy.
|
||||
</para>
|
||||
</refsect3>
|
||||
<refsect3 id="dynamic-langauge-without-ffi">
|
||||
</section>
|
||||
<section xml:id="dynamic-langauge-without-ffi">
|
||||
<title>Dynamic langauge without FFI</title>
|
||||
<para>
|
||||
PHP does not have FFI, unfortunately, so for this language a small native module implements the general <literal>vips_call()</literal> function for PHP language types, and a larger pure PHP layer makes it convenient to use.
|
||||
</para>
|
||||
</refsect3>
|
||||
<refsect3 id="gobject-introspection">
|
||||
</section>
|
||||
<section xml:id="gobject-introspection">
|
||||
<title>gobject-introspection</title>
|
||||
<para>
|
||||
The C source code to libvips has been marked up with special comments describing the interface in a standard way. These comments are read by the <literal>gobject-introspection</literal> package when libvips is compiled and used to generate a typelib, a description of how to call the library. Many languages have gobject-introspection packages: all you need to do to call libvips from your favorite language is to start g-o-i, load the libvips typelib, and you should have the whole library available. For example, from Python it’s as simple as:
|
||||
@ -177,8 +177,8 @@ from gi.repository import Vips
|
||||
<para>
|
||||
If you have a choice, I would recommend simply using FFI.
|
||||
</para>
|
||||
</refsect3>
|
||||
<refsect3 id="documentation">
|
||||
</section>
|
||||
<section xml:id="documentation">
|
||||
<title>Documentation</title>
|
||||
<para>
|
||||
You can generate searchable docs from a <code>.gir</code> (the thing that is built from scanning libvips and which in turn turn the typelib is made from) with <command>g-ir-doc-tool</command>, for example:
|
||||
@ -202,7 +202,7 @@ $ yelp-build html .
|
||||
<para>
|
||||
To make HTML docs. This is an easy way to see what you can call in the library.
|
||||
</para>
|
||||
</refsect3>
|
||||
</section>
|
||||
|
||||
|
||||
</refentry>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -15,7 +15,7 @@
|
||||
# <entry>vips_gamma()</entry>
|
||||
# </row>
|
||||
|
||||
from pyvips import Operation, Error, \
|
||||
from pyvips import Introspect, Operation, Error, \
|
||||
ffi, type_map, type_from_name, nickname_find
|
||||
|
||||
# for VipsOperationFlags
|
||||
@ -23,13 +23,15 @@ _OPERATION_DEPRECATED = 8
|
||||
|
||||
|
||||
def gen_function(operation_name):
|
||||
op = Operation.new_from_name(operation_name)
|
||||
intro = Introspect.get(operation_name)
|
||||
|
||||
print('<row>')
|
||||
print(' <entry>{}</entry>'.format(operation_name))
|
||||
print(' <entry>{}</entry>'.format(op.get_description().capitalize()))
|
||||
print(' <entry>vips_{}()</entry>'.format(operation_name))
|
||||
print('</row>')
|
||||
result = '<row>\n'
|
||||
result += ' <entry>{}</entry>\n'.format(operation_name)
|
||||
result += ' <entry>{}</entry>\n'.format(intro.description.capitalize())
|
||||
result += ' <entry>vips_{}()</entry>\n'.format(operation_name)
|
||||
result += '</row>'
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def gen_function_list():
|
||||
@ -39,10 +41,10 @@ def gen_function_list():
|
||||
nickname = nickname_find(gtype)
|
||||
try:
|
||||
# can fail for abstract types
|
||||
op = Operation.new_from_name(nickname)
|
||||
intro = Introspect.get(nickname)
|
||||
|
||||
# we are only interested in non-deprecated operations
|
||||
if (op.get_flags() & _OPERATION_DEPRECATED) == 0:
|
||||
if (intro.flags & _OPERATION_DEPRECATED) == 0:
|
||||
all_nicknames.append(nickname)
|
||||
except Error:
|
||||
pass
|
||||
@ -53,15 +55,50 @@ def gen_function_list():
|
||||
|
||||
type_map(type_from_name('VipsOperation'), add_nickname)
|
||||
|
||||
# add 'missing' synonyms by hand
|
||||
all_nicknames.append('crop')
|
||||
|
||||
# make list unique and sort
|
||||
all_nicknames = list(set(all_nicknames))
|
||||
all_nicknames.sort()
|
||||
|
||||
# make dict with overloads
|
||||
overloads = {
|
||||
'bandbool': ['bandand', 'bandor', 'bandeor', 'bandmean'],
|
||||
'bandjoin': ['bandjoin2'],
|
||||
'bandjoin_const': ['bandjoin_const1'],
|
||||
'boolean': ['andimage', 'orimage', 'eorimage', 'lshift', 'rshift'],
|
||||
'cast': ['cast_uchar', 'cast_char', 'cast_ushort', 'cast_short' 'cast_uint', 'cast_int', 'cast_float',
|
||||
'cast_double', 'cast_complex', 'cast_dpcomplex'],
|
||||
'complex': ['polar', 'rect', 'conj'],
|
||||
'complex2': ['cross_phase'],
|
||||
'complexget': ['real', 'imag'],
|
||||
'draw_circle': ['draw_circle1'],
|
||||
'draw_flood': ['draw_flood'],
|
||||
'draw_line': ['draw_line1'],
|
||||
'draw_mask': ['draw_mask1'],
|
||||
'draw_rect': ['rect', 'draw_rect1', 'draw_point', 'draw_point1'],
|
||||
'extract_area': ['crop'],
|
||||
'linear': ['linear1'],
|
||||
'math': ['sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'exp', 'exp10', 'log', 'log10'],
|
||||
'math2': ['pow', 'wop'],
|
||||
'rank': ['median'],
|
||||
'relational': ['equal', 'notequal', 'less', 'lesseq', 'more', 'moreeq'],
|
||||
'remainder_const': ['remainder_const1'],
|
||||
'round': ['floor', 'ceil', 'rint'],
|
||||
}
|
||||
|
||||
overloads['boolean_const'] = [o + '_const' for o in overloads['boolean']] + ['boolean_const1'] + \
|
||||
[o + '_const1' for o in overloads['boolean']]
|
||||
|
||||
overloads['math2_const'] = [o + '_const' for o in overloads['boolean']] + ['math2_const1'] + \
|
||||
[o + '_const1' for o in overloads['boolean']]
|
||||
|
||||
overloads['relational_const'] = [o + '_const' for o in overloads['relational']] + ['relational_const1'] + \
|
||||
[o + '_const1' for o in overloads['relational']]
|
||||
|
||||
for nickname in all_nicknames:
|
||||
gen_function(nickname)
|
||||
result = gen_function(nickname)
|
||||
if nickname in overloads:
|
||||
result = result.replace('()', '(), ' + (', '.join('vips_{}()'.format(n) for n in overloads[nickname])))
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -61,6 +61,8 @@
|
||||
<xi:include href="xml/object.xml"/>
|
||||
<xi:include href="xml/threadpool.xml"/>
|
||||
<xi:include href="xml/buf.xml"/>
|
||||
<xi:include href="xml/stream.xml"/>
|
||||
<xi:include href="xml/bufis.xml"/>
|
||||
<xi:include href="xml/basic.xml"/>
|
||||
</chapter>
|
||||
|
||||
|
28
fuzz/Makefile.am
Normal file
28
fuzz/Makefile.am
Normal file
@ -0,0 +1,28 @@
|
||||
TESTS = \
|
||||
test_fuzz.sh
|
||||
|
||||
FUZZPROGS = \
|
||||
jpegsave_file_fuzzer \
|
||||
jpegsave_buffer_fuzzer \
|
||||
pngsave_buffer_fuzzer \
|
||||
webpsave_buffer_fuzzer \
|
||||
sharpen_fuzzer \
|
||||
thumbnail_fuzzer \
|
||||
smartcrop_fuzzer \
|
||||
mosaic_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);
|
||||
}
|
||||
}
|
0
fuzz/common_fuzzer_corpus/.keep
Normal file
0
fuzz/common_fuzzer_corpus/.keep
Normal file
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 44 B |
Binary file not shown.
After Width: | Height: | Size: 289 B |
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 71 B |
@ -0,0 +1 @@
|
||||
GIF8 =・
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 166 B |
Binary file not shown.
After Width: | Height: | Size: 97 B |
15
fuzz/common_fuzzer_corpus/x-ascii.ppm
Normal file
15
fuzz/common_fuzzer_corpus/x-ascii.ppm
Normal file
@ -0,0 +1,15 @@
|
||||
P2
|
||||
#vips2ppm - Fri Aug 23 12:48:07 2019
|
||||
|
||||
10 10
|
||||
255
|
||||
96 101 113 118 124 130 136 141 147 150
|
||||
81 87 98 101 107 112 117 123 130 135
|
||||
73 78 85 90 95 99 103 110 118 124
|
||||
46 51 60 67 73 81 87 94 103 109
|
||||
34 35 40 48 60 69 77 81 85 88
|
||||
28 26 31 36 45 54 59 64 69 72
|
||||
32 31 41 39 39 40 45 52 61 66
|
||||
38 38 47 42 38 36 38 43 49 53
|
||||
37 38 39 39 37 37 37 36 34 32
|
||||
36 36 38 36 35 34 35 32 28 25
|
10
fuzz/common_fuzzer_corpus/x.csv
Normal file
10
fuzz/common_fuzzer_corpus/x.csv
Normal file
@ -0,0 +1,10 @@
|
||||
96 101 113 118 124 130 136 141 147 150
|
||||
81 87 98 101 107 112 117 123 130 135
|
||||
73 78 85 90 95 99 103 110 118 124
|
||||
46 51 60 67 73 81 87 94 103 109
|
||||
34 35 40 48 60 69 77 81 85 88
|
||||
28 26 31 36 45 54 59 64 69 72
|
||||
32 31 41 39 39 40 45 52 61 66
|
||||
38 38 47 42 38 36 38 43 49 53
|
||||
37 38 39 39 37 37 37 36 34 32
|
||||
36 36 38 36 35 34 35 32 28 25
|
|
11
fuzz/common_fuzzer_corpus/x.mat
Normal file
11
fuzz/common_fuzzer_corpus/x.mat
Normal file
@ -0,0 +1,11 @@
|
||||
10 10
|
||||
96 101 113 118 124 130 136 141 147 150
|
||||
81 87 98 101 107 112 117 123 130 135
|
||||
73 78 85 90 95 99 103 110 118 124
|
||||
46 51 60 67 73 81 87 94 103 109
|
||||
34 35 40 48 60 69 77 81 85 88
|
||||
28 26 31 36 45 54 59 64 69 72
|
||||
32 31 41 39 39 40 45 52 61 66
|
||||
38 38 47 42 38 36 38 43 49 53
|
||||
37 38 39 39 37 37 37 36 34 32
|
||||
36 36 38 36 35 34 35 32 28 25
|
6
fuzz/common_fuzzer_corpus/x.ppm
Normal file
6
fuzz/common_fuzzer_corpus/x.ppm
Normal file
@ -0,0 +1,6 @@
|
||||
P5
|
||||
#vips2ppm - Fri Aug 23 12:47:38 2019
|
||||
|
||||
10 10
|
||||
255
|
||||
`eqv|‚ˆ<E2809A>“–QWbekpu{‚‡INUZ_cgnv|.3<CIQW^gm"#(0<EMQUX$-6;@EH )''(-4=B&&/*&$&+15%&''%%%$" $$&$#"#
|
6
fuzz/common_fuzzer_corpus/x3.ppm
Normal file
6
fuzz/common_fuzzer_corpus/x3.ppm
Normal file
@ -0,0 +1,6 @@
|
||||
P6
|
||||
#vips2ppm - Fri Aug 23 12:47:50 2019
|
||||
|
||||
10 10
|
||||
255
|
||||
g[ilaoxm{{s€<73>yˆ†<E280A0>Œ…—<E280A6>‹œ•<C593>¤˜”¥\K[`Rai]klaophwtm}yr„wŒ„•‰…–TBRYHX^P_aUcf[kh_plcvrjzr‰€y‹:(6=-:E7DJ>LQDUWL]\SfcZolbzri|.(/)3#.9+8E7FM@QSHYVM`ZQf]Tg' %*$- *6(5=1?C6HG;OL@VOCW,!)!3$+2",0#-1#05(9</AE8LJ=Q1"%/#%7+/3&-/"+- */!04&7:+>>/B.""/##0$&/#'.!(.!*. --.+.)-," ,"!/##-!#,&+'-*+*'(#%
|
36
fuzz/jpegsave_buffer_fuzzer.cc
Normal file
36
fuzz/jpegsave_buffer_fuzzer.cc
Normal file
@ -0,0 +1,36 @@
|
||||
#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( image->Xsize > 100 ||
|
||||
image->Ysize > 100 ||
|
||||
image->Bands > 4 ) {
|
||||
g_object_unref( image );
|
||||
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 );
|
||||
}
|
60
fuzz/jpegsave_file_fuzzer.cc
Normal file
60
fuzz/jpegsave_file_fuzzer.cc
Normal file
@ -0,0 +1,60 @@
|
||||
#include <vips/vips.h>
|
||||
|
||||
extern "C" int
|
||||
LLVMFuzzerInitialize( int *argc, char ***argv )
|
||||
{
|
||||
vips_concurrency_set( 1 );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
test_one_file( const char *name )
|
||||
{
|
||||
VipsImage *image;
|
||||
void *buf;
|
||||
size_t len;
|
||||
|
||||
if( !(image = vips_image_new_from_file( name,
|
||||
"access", VIPS_ACCESS_SEQUENTIAL,
|
||||
NULL )) )
|
||||
return( 0 );
|
||||
|
||||
if( image->Xsize > 100 ||
|
||||
image->Ysize > 100 ||
|
||||
image->Bands > 4 ) {
|
||||
g_object_unref( image );
|
||||
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 );
|
||||
}
|
||||
|
||||
extern "C" int
|
||||
LLVMFuzzerTestOneInput( const guint8 *data, size_t size )
|
||||
{
|
||||
char *name;
|
||||
|
||||
if( !(name = vips__temp_name( "%s" )) )
|
||||
return( 0 );
|
||||
|
||||
if( !g_file_set_contents( name, (const char *) data, size, NULL ) ||
|
||||
test_one_file( name ) ) {
|
||||
g_unlink( name );
|
||||
g_free( name );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
g_unlink( name );
|
||||
g_free( name );
|
||||
|
||||
return( 0 );
|
||||
}
|
61
fuzz/mosaic_fuzzer.cc
Normal file
61
fuzz/mosaic_fuzzer.cc
Normal file
@ -0,0 +1,61 @@
|
||||
#include <vips/vips.h>
|
||||
|
||||
struct mosaic_opt {
|
||||
guint8 dir : 1;
|
||||
guint16 xref;
|
||||
guint16 yref;
|
||||
guint16 xsec;
|
||||
guint16 ysec;
|
||||
};
|
||||
|
||||
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 *ref, *sec, *out;
|
||||
struct mosaic_opt *opt;
|
||||
double d;
|
||||
|
||||
if( size < sizeof( struct mosaic_opt ) )
|
||||
return( 0 );
|
||||
|
||||
if( !(ref = vips_image_new_from_buffer( data, size, "", NULL )) )
|
||||
return( 0 );
|
||||
|
||||
if( ref->Xsize > 100 ||
|
||||
ref->Ysize > 100 ||
|
||||
ref->Bands > 4 ) {
|
||||
g_object_unref( ref );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
if( vips_rot180( ref, &sec, NULL ) ) {
|
||||
g_object_unref( ref );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Extract some bytes from the tail to fuzz the arguments of the API.
|
||||
*/
|
||||
opt = (struct mosaic_opt *) (data + size - sizeof( struct mosaic_opt ));
|
||||
|
||||
if( vips_mosaic( ref, sec, &out, (VipsDirection) opt->dir,
|
||||
opt->xref, opt->yref, opt->xsec, opt->ysec, NULL ) ) {
|
||||
g_object_unref( sec );
|
||||
g_object_unref( ref );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
vips_max( out, &d, NULL );
|
||||
|
||||
g_object_unref( out );
|
||||
g_object_unref( sec );
|
||||
g_object_unref( ref );
|
||||
|
||||
return( 0 );
|
||||
}
|
36
fuzz/pngsave_buffer_fuzzer.cc
Normal file
36
fuzz/pngsave_buffer_fuzzer.cc
Normal file
@ -0,0 +1,36 @@
|
||||
#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( image->Xsize > 100 ||
|
||||
image->Ysize > 100 ||
|
||||
image->Bands > 4 ) {
|
||||
g_object_unref( image );
|
||||
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 );
|
||||
}
|
37
fuzz/sharpen_fuzzer.cc
Normal file
37
fuzz/sharpen_fuzzer.cc
Normal file
@ -0,0 +1,37 @@
|
||||
#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, *out;
|
||||
double d;
|
||||
|
||||
if( !(image = vips_image_new_from_buffer( data, size, "", NULL )) )
|
||||
return( 0 );
|
||||
|
||||
if( image->Xsize > 100 ||
|
||||
image->Ysize > 100 ||
|
||||
image->Bands > 4 ) {
|
||||
g_object_unref( image );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
if( vips_sharpen( image, &out, NULL ) ) {
|
||||
g_object_unref( image );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
vips_avg( out, &d, NULL );
|
||||
|
||||
g_object_unref( out );
|
||||
g_object_unref( image );
|
||||
|
||||
return( 0 );
|
||||
}
|
37
fuzz/smartcrop_fuzzer.cc
Normal file
37
fuzz/smartcrop_fuzzer.cc
Normal file
@ -0,0 +1,37 @@
|
||||
#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, *out;
|
||||
double d;
|
||||
|
||||
if( !(image = vips_image_new_from_buffer( data, size, "", NULL )) )
|
||||
return( 0 );
|
||||
|
||||
if( image->Xsize > 100 ||
|
||||
image->Ysize > 100 ||
|
||||
image->Bands > 4 ) {
|
||||
g_object_unref( image );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
if( vips_smartcrop( image, &out, 32, 32, NULL ) ) {
|
||||
g_object_unref( image );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
vips_min( out, &d, NULL );
|
||||
|
||||
g_object_unref( out );
|
||||
g_object_unref( image );
|
||||
|
||||
return( 0 );
|
||||
}
|
25
fuzz/test_fuzz.sh
Executable file
25
fuzz/test_fuzz.sh
Executable file
@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
|
||||
#set -x
|
||||
set -e
|
||||
|
||||
# Glib is built 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"
|
||||
export UBSAN_OPTIONS="print_stacktrace=1"
|
||||
|
||||
# Hide all warning messages from vips.
|
||||
export VIPS_WARNING=0
|
||||
|
||||
ret=0
|
||||
|
||||
for fuzzer in *_fuzzer; do
|
||||
for file in common_fuzzer_corpus/*; do
|
||||
if ! ./$fuzzer $file; then
|
||||
echo FAIL $fuzzer $file
|
||||
ret=1
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
exit $ret
|
37
fuzz/thumbnail_fuzzer.cc
Normal file
37
fuzz/thumbnail_fuzzer.cc
Normal file
@ -0,0 +1,37 @@
|
||||
#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, *out;
|
||||
double d;
|
||||
|
||||
if( !(image = vips_image_new_from_buffer( data, size, "", NULL )) )
|
||||
return( 0 );
|
||||
|
||||
if( image->Xsize > 100 ||
|
||||
image->Ysize > 100 ||
|
||||
image->Bands > 4 ) {
|
||||
g_object_unref( image );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
if( vips_thumbnail_image( image, &out, 42, NULL ) ) {
|
||||
g_object_unref( image );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
vips_avg( out, &d, NULL );
|
||||
|
||||
g_object_unref( out );
|
||||
g_object_unref( image );
|
||||
|
||||
return( 0 );
|
||||
}
|
36
fuzz/webpsave_buffer_fuzzer.cc
Normal file
36
fuzz/webpsave_buffer_fuzzer.cc
Normal file
@ -0,0 +1,36 @@
|
||||
#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( image->Xsize > 100 ||
|
||||
image->Ysize > 100 ||
|
||||
image->Bands > 4 ) {
|
||||
g_object_unref( image );
|
||||
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 );
|
||||
}
|
@ -87,7 +87,7 @@ AM_LDFLAGS = \
|
||||
LDADD = @INTROSPECTION_LIBS@ @VIPS_CFLAGS@ libvips.la @VIPS_LIBS@
|
||||
|
||||
noinst_PROGRAMS = \
|
||||
introspect
|
||||
introspect$(EXEEXT)
|
||||
introspect_SOURCES = \
|
||||
introspect.c
|
||||
|
||||
@ -96,7 +96,7 @@ introspect_SOURCES = \
|
||||
introspection_sources = @vips_introspection_sources@
|
||||
|
||||
# we make the vips8 API
|
||||
Vips-8.0.gir: introspect
|
||||
Vips-8.0.gir: introspect$(EXEEXT)
|
||||
Vips_8_0_gir_INCLUDES = GObject-2.0
|
||||
Vips_8_0_gir_CFLAGS = $(INCLUDES) -I${top_srcdir}/libvips/include
|
||||
Vips_8_0_gir_LIBS = libvips.la
|
||||
|
@ -73,6 +73,7 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/internal.h>
|
||||
|
||||
#include "binary.h"
|
||||
#include "unaryconst.h"
|
||||
@ -140,6 +141,15 @@ vips_boolean_build( VipsObject *object )
|
||||
g_assert_not_reached(); \
|
||||
}
|
||||
|
||||
#define FNLOOP( TYPE, FN ) { \
|
||||
TYPE * restrict left = (TYPE *) in[0]; \
|
||||
TYPE * restrict right = (TYPE *) in[1]; \
|
||||
int * restrict q = (int *) out; \
|
||||
\
|
||||
for( x = 0; x < sz; x++ ) \
|
||||
q[x] = FN( left[x], right[x] ); \
|
||||
}
|
||||
|
||||
static void
|
||||
vips_boolean_buffer( VipsArithmetic *arithmetic,
|
||||
VipsPel *out, VipsPel **in, int width )
|
||||
@ -163,8 +173,30 @@ vips_boolean_buffer( VipsArithmetic *arithmetic,
|
||||
SWITCH( LOOP, FLOOP, ^ );
|
||||
break;
|
||||
|
||||
/* Special case: we need to be able to use VIPS_LSHIFT_INT().
|
||||
*/
|
||||
case VIPS_OPERATION_BOOLEAN_LSHIFT:
|
||||
SWITCH( LOOP, FLOOP, << );
|
||||
switch( vips_image_get_format( im ) ) {
|
||||
case VIPS_FORMAT_UCHAR:
|
||||
LOOP( unsigned char, << ); break;
|
||||
case VIPS_FORMAT_CHAR:
|
||||
FNLOOP( signed char, VIPS_LSHIFT_INT ); break;
|
||||
case VIPS_FORMAT_USHORT:
|
||||
LOOP( unsigned short, << ); break;
|
||||
case VIPS_FORMAT_SHORT:
|
||||
FNLOOP( signed short, VIPS_LSHIFT_INT ); break;
|
||||
case VIPS_FORMAT_UINT:
|
||||
LOOP( unsigned int, << ); break;
|
||||
case VIPS_FORMAT_INT:
|
||||
FNLOOP( signed int, VIPS_LSHIFT_INT ); break;
|
||||
case VIPS_FORMAT_FLOAT:
|
||||
FLOOP( float, << ); break;
|
||||
case VIPS_FORMAT_DOUBLE:
|
||||
FLOOP( double, << ); break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
break;
|
||||
|
||||
case VIPS_OPERATION_BOOLEAN_RSHIFT:
|
||||
@ -426,14 +458,11 @@ vips_boolean_const_build( VipsObject *object )
|
||||
{
|
||||
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
|
||||
VipsUnary *unary = (VipsUnary *) object;
|
||||
VipsUnaryConst *uconst = (VipsUnaryConst *) object;
|
||||
|
||||
if( unary->in &&
|
||||
vips_check_noncomplex( class->nickname, unary->in ) )
|
||||
return( -1 );
|
||||
|
||||
uconst->const_format = VIPS_FORMAT_INT;
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_boolean_const_parent_class )->
|
||||
build( object ) )
|
||||
return( -1 );
|
||||
@ -442,9 +471,9 @@ vips_boolean_const_build( VipsObject *object )
|
||||
}
|
||||
|
||||
#define LOOPC( TYPE, OP ) { \
|
||||
TYPE *p = (TYPE *) in[0]; \
|
||||
TYPE *q = (TYPE *) out; \
|
||||
int *c = (int *) uconst->c_ready; \
|
||||
TYPE * restrict p = (TYPE *) in[0]; \
|
||||
TYPE * restrict q = (TYPE *) out; \
|
||||
int * restrict c = uconst->c_int; \
|
||||
\
|
||||
for( i = 0, x = 0; x < width; x++ ) \
|
||||
for( b = 0; b < bands; b++, i++ ) \
|
||||
@ -452,9 +481,9 @@ vips_boolean_const_build( VipsObject *object )
|
||||
}
|
||||
|
||||
#define FLOOPC( TYPE, OP ) { \
|
||||
TYPE *p = (TYPE *) in[0]; \
|
||||
int *q = (int *) out; \
|
||||
int *c = (int *) uconst->c_ready; \
|
||||
TYPE * restrict p = (TYPE *) in[0]; \
|
||||
int * restrict q = (int *) out; \
|
||||
int * restrict c = uconst->c_int; \
|
||||
\
|
||||
for( i = 0, x = 0; x < width; x++ ) \
|
||||
for( b = 0; b < bands; b++, i++ ) \
|
||||
|
@ -268,6 +268,8 @@ vips_find_trim_init( VipsFindTrim *find_trim )
|
||||
*
|
||||
* @threshold defaults to 10.
|
||||
*
|
||||
* The image needs to be at least 3x3 pixels in size.
|
||||
*
|
||||
* See also: vips_getpoint(), vips_extract_area(), vips_smartcrop().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
|
@ -150,11 +150,12 @@ vips_hough_circle_vote_endpoints_clip( VipsImage *image,
|
||||
int y, int x1, int x2, int quadrant, void *client )
|
||||
{
|
||||
int r = *((int *) client);
|
||||
guint *line = (guint *) VIPS_IMAGE_ADDR( image, 0, y ) + r;
|
||||
int b = image->Bands;
|
||||
|
||||
if( y >= 0 &&
|
||||
y < image->Ysize ) {
|
||||
guint *line = (guint *) VIPS_IMAGE_ADDR( image, 0, y ) + r;
|
||||
|
||||
if( x1 >=0 &&
|
||||
x1 < image->Xsize )
|
||||
line[x1 * b] += 1;
|
||||
|
@ -338,14 +338,11 @@ vips_math2_const_build( VipsObject *object )
|
||||
{
|
||||
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
|
||||
VipsUnary *unary = (VipsUnary *) object;
|
||||
VipsUnaryConst *uconst = (VipsUnaryConst *) object;
|
||||
|
||||
if( unary->in &&
|
||||
vips_check_noncomplex( class->nickname, unary->in ) )
|
||||
return( -1 );
|
||||
|
||||
uconst->const_format = VIPS_FORMAT_DOUBLE;
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_math2_const_parent_class )->
|
||||
build( object ) )
|
||||
return( -1 );
|
||||
@ -356,7 +353,7 @@ vips_math2_const_build( VipsObject *object )
|
||||
#define LOOPC( IN, OUT, OP ) { \
|
||||
IN * restrict p = (IN *) in[0]; \
|
||||
OUT * restrict q = (OUT *) out; \
|
||||
double * restrict c = (double *) uconst->c_ready; \
|
||||
double * restrict c = uconst->c_double; \
|
||||
\
|
||||
for( i = 0, x = 0; x < width; x++ ) \
|
||||
for( b = 0; b < bands; b++, i++ ) \
|
||||
|
@ -457,25 +457,18 @@ typedef VipsUnaryConstClass VipsRelationalConstClass;
|
||||
G_DEFINE_TYPE( VipsRelationalConst,
|
||||
vips_relational_const, VIPS_TYPE_UNARY_CONST );
|
||||
|
||||
static int
|
||||
vips_relational_const_build( VipsObject *object )
|
||||
{
|
||||
VipsUnary *unary = (VipsUnary *) object;
|
||||
VipsUnaryConst *uconst = (VipsUnaryConst *) object;
|
||||
|
||||
if( unary->in )
|
||||
uconst->const_format = unary->in->BandFmt;
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_relational_const_parent_class )->
|
||||
build( object ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
#define RLOOPCI( TYPE, OP ) { \
|
||||
TYPE * restrict p = (TYPE *) in[0]; \
|
||||
int * restrict c = uconst->c_int; \
|
||||
\
|
||||
for( i = 0, x = 0; x < width; x++ ) \
|
||||
for( b = 0; b < bands; b++, i++ ) \
|
||||
out[i] = (p[i] OP c[b]) ? 255 : 0; \
|
||||
}
|
||||
|
||||
#define RLOOPC( TYPE, OP ) { \
|
||||
#define RLOOPCF( TYPE, OP ) { \
|
||||
TYPE * restrict p = (TYPE *) in[0]; \
|
||||
TYPE * restrict c = (TYPE *) uconst->c_ready; \
|
||||
double * restrict c = uconst->c_double; \
|
||||
\
|
||||
for( i = 0, x = 0; x < width; x++ ) \
|
||||
for( b = 0; b < bands; b++, i++ ) \
|
||||
@ -486,7 +479,7 @@ vips_relational_const_build( VipsObject *object )
|
||||
TYPE * restrict p = (TYPE *) in[0]; \
|
||||
\
|
||||
for( i = 0, x = 0; x < width; x++ ) { \
|
||||
TYPE * restrict c = (TYPE *) uconst->c_ready; \
|
||||
double * restrict c = uconst->c_double; \
|
||||
\
|
||||
for( b = 0; b < bands; b++, i++ ) { \
|
||||
out[i] = OP( p[0], p[1], c[0], c[1]) ? 255 : 0; \
|
||||
@ -505,32 +498,64 @@ vips_relational_const_buffer( VipsArithmetic *arithmetic,
|
||||
VipsRelationalConst *rconst = (VipsRelationalConst *) arithmetic;
|
||||
VipsImage *im = arithmetic->ready[0];
|
||||
int bands = im->Bands;
|
||||
gboolean is_int = uconst->is_int &&
|
||||
vips_band_format_isint( im->BandFmt );
|
||||
|
||||
int i, x, b;
|
||||
|
||||
switch( rconst->relational ) {
|
||||
case VIPS_OPERATION_RELATIONAL_EQUAL:
|
||||
SWITCH( RLOOPC, CLOOPC, ==, CEQUAL );
|
||||
case VIPS_OPERATION_RELATIONAL_EQUAL:
|
||||
if( is_int ) {
|
||||
SWITCH( RLOOPCI, CLOOPC, ==, CEQUAL );
|
||||
}
|
||||
else {
|
||||
SWITCH( RLOOPCF, CLOOPC, ==, CEQUAL );
|
||||
}
|
||||
break;
|
||||
|
||||
case VIPS_OPERATION_RELATIONAL_NOTEQ:
|
||||
SWITCH( RLOOPC, CLOOPC, !=, CNOTEQ );
|
||||
if( is_int ) {
|
||||
SWITCH( RLOOPCI, CLOOPC, !=, CNOTEQ );
|
||||
}
|
||||
else {
|
||||
SWITCH( RLOOPCF, CLOOPC, !=, CNOTEQ );
|
||||
}
|
||||
break;
|
||||
|
||||
case VIPS_OPERATION_RELATIONAL_LESS:
|
||||
SWITCH( RLOOPC, CLOOPC, <, CLESS );
|
||||
case VIPS_OPERATION_RELATIONAL_LESS:
|
||||
if( is_int ) {
|
||||
SWITCH( RLOOPCI, CLOOPC, <, CLESS );
|
||||
}
|
||||
else {
|
||||
SWITCH( RLOOPCF, CLOOPC, <, CLESS );
|
||||
}
|
||||
break;
|
||||
|
||||
case VIPS_OPERATION_RELATIONAL_LESSEQ:
|
||||
SWITCH( RLOOPC, CLOOPC, <=, CLESSEQ );
|
||||
case VIPS_OPERATION_RELATIONAL_LESSEQ:
|
||||
if( is_int ) {
|
||||
SWITCH( RLOOPCI, CLOOPC, <=, CLESSEQ );
|
||||
}
|
||||
else {
|
||||
SWITCH( RLOOPCF, CLOOPC, <=, CLESSEQ );
|
||||
}
|
||||
break;
|
||||
|
||||
case VIPS_OPERATION_RELATIONAL_MORE:
|
||||
SWITCH( RLOOPC, CLOOPC, >, CMORE );
|
||||
case VIPS_OPERATION_RELATIONAL_MORE:
|
||||
if( is_int ) {
|
||||
SWITCH( RLOOPCI, CLOOPC, >, CMORE );
|
||||
}
|
||||
else {
|
||||
SWITCH( RLOOPCF, CLOOPC, >, CMORE );
|
||||
}
|
||||
break;
|
||||
|
||||
case VIPS_OPERATION_RELATIONAL_MOREEQ:
|
||||
SWITCH( RLOOPC, CLOOPC, >=, CMOREEQ );
|
||||
case VIPS_OPERATION_RELATIONAL_MOREEQ:
|
||||
if( is_int ) {
|
||||
SWITCH( RLOOPCI, CLOOPC, >=, CMOREEQ );
|
||||
}
|
||||
else {
|
||||
SWITCH( RLOOPCF, CLOOPC, >=, CMOREEQ );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -551,7 +576,6 @@ vips_relational_const_class_init( VipsRelationalConstClass *class )
|
||||
object_class->nickname = "relational_const";
|
||||
object_class->description =
|
||||
_( "relational operations against a constant" );
|
||||
object_class->build = vips_relational_const_build;
|
||||
|
||||
aclass->process_line = vips_relational_const_buffer;
|
||||
|
||||
|
@ -238,15 +238,11 @@ vips_remainder_const_build( VipsObject *object )
|
||||
{
|
||||
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
|
||||
VipsUnary *unary = (VipsUnary *) object;
|
||||
VipsUnaryConst *uconst = (VipsUnaryConst *) object;
|
||||
|
||||
if( unary->in &&
|
||||
vips_check_noncomplex( class->nickname, unary->in ) )
|
||||
return( -1 );
|
||||
|
||||
if( unary->in )
|
||||
uconst->const_format = unary->in->BandFmt;
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_remainder_const_parent_class )->
|
||||
build( object ) )
|
||||
return( -1 );
|
||||
@ -259,7 +255,7 @@ vips_remainder_const_build( VipsObject *object )
|
||||
#define IREMAINDERCONST( TYPE ) { \
|
||||
TYPE * restrict p = (TYPE *) in[0]; \
|
||||
TYPE * restrict q = (TYPE *) out; \
|
||||
TYPE * restrict c = (TYPE *) uconst->c_ready; \
|
||||
int * restrict c = uconst->c_int; \
|
||||
\
|
||||
for( i = 0, x = 0; x < width; x++ ) \
|
||||
for( b = 0; b < bands; b++, i++ ) \
|
||||
@ -271,7 +267,7 @@ vips_remainder_const_build( VipsObject *object )
|
||||
#define FREMAINDERCONST( TYPE ) { \
|
||||
TYPE * restrict p = (TYPE *) in[0]; \
|
||||
TYPE * restrict q = (TYPE *) out; \
|
||||
TYPE * restrict c = (TYPE *) uconst->c_ready; \
|
||||
int * restrict c = uconst->c_int; \
|
||||
\
|
||||
for( i = 0, x = 0; x < width; x++ ) \
|
||||
for( b = 0; b < bands; b++, i++ ) { \
|
||||
|
@ -2,6 +2,8 @@
|
||||
*
|
||||
* 11/11/11
|
||||
* - from arith_binary_const
|
||||
* 21/8/19
|
||||
* - revise to fix out of range comparisons
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -42,6 +44,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
|
||||
@ -49,100 +52,6 @@
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE( VipsUnaryConst, vips_unary_const, VIPS_TYPE_UNARY );
|
||||
|
||||
/* Cast a vector of double to a vector of TYPE, clipping to a range.
|
||||
*/
|
||||
#define CAST_CLIP( TYPE, N, X ) { \
|
||||
TYPE * restrict tq = (TYPE *) q; \
|
||||
\
|
||||
for( i = 0; i < m; i++ ) { \
|
||||
double v = p[VIPS_MIN( n - 1, i )]; \
|
||||
\
|
||||
tq[i] = (TYPE) VIPS_FCLIP( N, v, X ); \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Cast a vector of double to a vector of TYPE.
|
||||
*/
|
||||
#define CAST( TYPE ) { \
|
||||
TYPE * restrict tq = (TYPE *) q; \
|
||||
\
|
||||
for( i = 0; i < m; i++ ) \
|
||||
tq[i] = (TYPE) p[VIPS_MIN( n - 1, i )]; \
|
||||
}
|
||||
|
||||
/* Cast a vector of double to a complex vector of TYPE.
|
||||
*/
|
||||
#define CASTC( TYPE ) { \
|
||||
TYPE * restrict tq = (TYPE *) q; \
|
||||
\
|
||||
for( i = 0; i < m; i++ ) { \
|
||||
tq[0] = (TYPE) p[VIPS_MIN( n - 1, i )]; \
|
||||
tq[1] = 0; \
|
||||
\
|
||||
tq += 2; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Cast a n-band vector of double to a m-band vector in another format.
|
||||
*/
|
||||
static VipsPel *
|
||||
make_pixel( VipsObject *obj,
|
||||
int m, VipsBandFormat fmt, int n, double * restrict p )
|
||||
{
|
||||
VipsPel *q;
|
||||
int i;
|
||||
|
||||
if( !(q = VIPS_ARRAY( obj, m * vips_format_sizeof( fmt ), VipsPel )) )
|
||||
return( NULL );
|
||||
|
||||
switch( fmt ) {
|
||||
case VIPS_FORMAT_CHAR:
|
||||
CAST_CLIP( signed char, SCHAR_MIN, SCHAR_MAX );
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_UCHAR:
|
||||
CAST_CLIP( unsigned char, 0, UCHAR_MAX );
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_SHORT:
|
||||
CAST_CLIP( signed short, SCHAR_MIN, SCHAR_MAX );
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_USHORT:
|
||||
CAST_CLIP( unsigned short, 0, USHRT_MAX );
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_INT:
|
||||
CAST_CLIP( signed int, INT_MIN, INT_MAX );
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_UINT:
|
||||
CAST_CLIP( unsigned int, 0, UINT_MAX );
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_FLOAT:
|
||||
CAST( float );
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_DOUBLE:
|
||||
CAST( double );
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_COMPLEX:
|
||||
CASTC( float );
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_DPCOMPLEX:
|
||||
CASTC( double );
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
return( q );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_unary_const_build( VipsObject *object )
|
||||
{
|
||||
@ -161,27 +70,54 @@ vips_unary_const_build( VipsObject *object )
|
||||
uconst->n = VIPS_MAX( uconst->n, unary->in->Bands );
|
||||
arithmetic->base_bands = uconst->n;
|
||||
|
||||
if( unary->in && uconst->c ) {
|
||||
if( unary->in &&
|
||||
uconst->c ) {
|
||||
if( vips_check_vector( class->nickname,
|
||||
uconst->c->n, unary->in ) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* Some operations need the vector in the input type (eg.
|
||||
* im_equal_vec() where the output type is always uchar and is useless
|
||||
* for comparisons), some need it in the output type (eg.
|
||||
* im_andimage_vec() where we want to get the double to an int so we
|
||||
* can do bitwise-and without having to cast for each pixel), some
|
||||
* need a fixed type (eg. im_powtra_vec(), where we want to keep it as
|
||||
* double).
|
||||
/* Some operations need int constants, for example boolean AND, SHIFT
|
||||
* etc.
|
||||
*
|
||||
* Therefore pass in the desired vector type as a param.
|
||||
* Some can use int constants as an optimisation, for example (x <
|
||||
* 12). It depends on the value though: obviously (x < 12.5) should
|
||||
* not use the int form.
|
||||
*
|
||||
* For complex images, we double the vector length and set the
|
||||
* imaginary part to 0.
|
||||
*/
|
||||
if( uconst->c ) {
|
||||
gboolean is_complex =
|
||||
vips_band_format_iscomplex( unary->in->BandFmt );
|
||||
int step = is_complex ? 2 : 1;
|
||||
int n = step * uconst->n;
|
||||
double *c = (double *) uconst->c->data;
|
||||
|
||||
if( uconst->c )
|
||||
uconst->c_ready = make_pixel( (VipsObject *) uconst,
|
||||
uconst->n, uconst->const_format,
|
||||
uconst->c->n, (double *) uconst->c->data );
|
||||
int i;
|
||||
|
||||
uconst->c_int = VIPS_ARRAY( object, n, int );
|
||||
uconst->c_double = VIPS_ARRAY( object, n, double );
|
||||
if( !uconst->c_int ||
|
||||
!uconst->c_double )
|
||||
return( -1 );
|
||||
memset( uconst->c_int, 0, n * sizeof( int ) );
|
||||
memset( uconst->c_double, 0, n * sizeof( double ) );
|
||||
|
||||
for( i = 0; i < n; i += step )
|
||||
uconst->c_double[i] =
|
||||
c[VIPS_MIN( i / step, uconst->c->n - 1)];
|
||||
|
||||
for( i = 0; i < n; i += step )
|
||||
uconst->c_int[i] = uconst->c_double[i];
|
||||
|
||||
uconst->is_int = TRUE;
|
||||
for( i = 0; i < n; i += step )
|
||||
if( uconst->c_int[i] != uconst->c_double[i] ) {
|
||||
uconst->is_int = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_unary_const_parent_class )->
|
||||
build( object ) )
|
||||
|
@ -59,16 +59,15 @@ typedef struct _VipsUnaryConst {
|
||||
*/
|
||||
VipsArea *c;
|
||||
|
||||
/* The format the constant should be cast to. Subclasses set this
|
||||
* ready for unaryconst's build method.
|
||||
*/
|
||||
VipsBandFormat const_format;
|
||||
|
||||
/* Our constant expanded to match arith->ready in size and
|
||||
* const_format in type.
|
||||
/* Our constant expanded to match arith->ready in size. We need int
|
||||
* and double versions.
|
||||
*
|
||||
* is_int is TRUE if the two arrays are equal for every element.
|
||||
*/
|
||||
int n;
|
||||
VipsPel *c_ready;
|
||||
int *c_int;
|
||||
double *c_double;
|
||||
gboolean is_int;
|
||||
|
||||
} VipsUnaryConst;
|
||||
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/internal.h>
|
||||
|
||||
#include "pcolour.h"
|
||||
|
||||
@ -95,12 +96,12 @@ vips_LabQ2Lab_line( VipsColour *colour, VipsPel *out, VipsPel **in, int width )
|
||||
|
||||
/* Build a.
|
||||
*/
|
||||
l = (p[1] << 3) | ((lsbs >> 3) & 0x7);
|
||||
l = VIPS_LSHIFT_INT( p[1], 3) | ((lsbs >> 3) & 0x7);
|
||||
q[1] = (float) l * 0.125;
|
||||
|
||||
/* And b.
|
||||
*/
|
||||
l = (p[2] << 3) | (lsbs & 0x7);
|
||||
l = VIPS_LSHIFT_INT( p[2], 3) | (lsbs & 0x7);
|
||||
q[2] = (float) l * 0.125;
|
||||
|
||||
p += 4;
|
||||
|
@ -1,5 +1,7 @@
|
||||
noinst_LTLIBRARIES = libcolour.la
|
||||
|
||||
SUBDIRS = profiles
|
||||
|
||||
libcolour_la_SOURCES = \
|
||||
profiles.c \
|
||||
profiles.h \
|
||||
@ -42,7 +44,6 @@ profiles.c:
|
||||
./wrap-profiles.sh profiles profiles.c
|
||||
|
||||
EXTRA_DIST = \
|
||||
profiles \
|
||||
wrap-profiles.sh
|
||||
|
||||
AM_CPPFLAGS = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@
|
||||
|
@ -127,7 +127,7 @@ make_hI( void )
|
||||
for( i = 0; i < 361; i++ ) {
|
||||
int k;
|
||||
|
||||
for( k = 0; k < 360 && hl[j][k] <= i; k++ )
|
||||
for( k = 1; k < 360 && hl[j][k] <= i; k++ )
|
||||
;
|
||||
|
||||
hI[j][i] = k - 1 + (i - hl[j][k - 1]) /
|
||||
|
@ -7,7 +7,9 @@
|
||||
* - gtkdoc
|
||||
* - cleanups
|
||||
* 20/9/12
|
||||
* redo as a class
|
||||
* - redo as a class
|
||||
* 29/8/19
|
||||
* - avoid /0
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -67,18 +69,26 @@ vips_Yxy2XYZ_line( VipsColour *colour, VipsPel *out, VipsPel **in, int width )
|
||||
float x = p[1];
|
||||
float y = p[2];
|
||||
|
||||
double total;
|
||||
float X, Z;
|
||||
|
||||
p += 3;
|
||||
if( x == 0.0 ||
|
||||
y == 0.0 ) {
|
||||
X = 0.0;
|
||||
Z = 0.0;
|
||||
}
|
||||
else {
|
||||
double total;
|
||||
|
||||
total = Y / y;
|
||||
X = x * total;
|
||||
Z = (X - x * X - x * Y) / x;
|
||||
total = Y / y;
|
||||
X = x * total;
|
||||
Z = (X - x * X - x * Y) / x;
|
||||
}
|
||||
|
||||
q[0] = X;
|
||||
q[1] = Y;
|
||||
q[2] = Z;
|
||||
|
||||
p += 3;
|
||||
q += 3;
|
||||
}
|
||||
}
|
||||
|
@ -58,58 +58,19 @@ typedef VipsOperationClass VipsProfileLoadClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsProfileLoad, vips_profile_load, VIPS_TYPE_OPERATION );
|
||||
|
||||
/* Created on first use from a base64 string in profiles.c.
|
||||
*/
|
||||
typedef struct _VipsFallbackProfile {
|
||||
const char *name;
|
||||
void *data;
|
||||
size_t data_length;
|
||||
} VipsFallbackProfile;
|
||||
|
||||
static GSList *vips_fallback_profile_list = NULL;
|
||||
|
||||
static void *
|
||||
vips_fallback_profile_get_init( void )
|
||||
static const void *
|
||||
vips_profile_fallback_get( const char *name, size_t *length )
|
||||
{
|
||||
int i;
|
||||
VipsProfileFallback *fallback;
|
||||
|
||||
for( i = 0; vips__coded_profiles[i].name; i++ ) {
|
||||
size_t data_length;
|
||||
unsigned char *data;
|
||||
VipsFallbackProfile *fallback;
|
||||
|
||||
if( !(data = vips__b64_decode(
|
||||
vips__coded_profiles[i].data, &data_length )) )
|
||||
return( NULL );
|
||||
fallback = g_new( VipsFallbackProfile,1 );
|
||||
fallback->name = vips__coded_profiles[i].name;
|
||||
fallback->data = data;
|
||||
fallback->data_length = data_length;
|
||||
vips_fallback_profile_list = g_slist_prepend(
|
||||
vips_fallback_profile_list, fallback );
|
||||
}
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
static void *
|
||||
vips_fallback_profile_get( const char *name, size_t *length )
|
||||
{
|
||||
static GOnce once = G_ONCE_INIT;
|
||||
|
||||
GSList *p;
|
||||
|
||||
VIPS_ONCE( &once, (GThreadFunc) vips_fallback_profile_get_init, NULL );
|
||||
|
||||
for( p = vips_fallback_profile_list; p; p = p->next ) {
|
||||
VipsFallbackProfile *fallback = (VipsFallbackProfile *) p->data;
|
||||
|
||||
for( i = 0; (fallback = vips__profile_fallback_table[i]); i++ )
|
||||
if( g_ascii_strcasecmp( fallback->name, name ) == 0 ) {
|
||||
*length = fallback->data_length;
|
||||
if( length )
|
||||
*length = fallback->length;
|
||||
|
||||
return( fallback->data );
|
||||
}
|
||||
}
|
||||
|
||||
return( NULL );
|
||||
}
|
||||
@ -131,7 +92,7 @@ vips_profile_load_build( VipsObject *object )
|
||||
if( g_ascii_strcasecmp( load->name, "none" ) == 0 ) {
|
||||
profile = NULL;
|
||||
}
|
||||
else if( (data = vips_fallback_profile_get( load->name, &length )) ) {
|
||||
else if( (data = vips_profile_fallback_get( load->name, &length )) ) {
|
||||
profile = vips_blob_new( NULL, data, length );
|
||||
}
|
||||
else if( (data = vips__file_read_name( load->name,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,13 @@
|
||||
/* The fallback profiles, coded as a set of base64 strings, see
|
||||
* wrap-profiles.sh
|
||||
/* The fallback profiles, coded as a set of uchar arrays, see wrap-profiles.sh
|
||||
*/
|
||||
typedef struct _VipsCodedProfile {
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct _VipsProfileFallback {
|
||||
const char *name;
|
||||
const char *data;
|
||||
} VipsCodedProfile;
|
||||
size_t length;
|
||||
const unsigned char data[];
|
||||
} VipsProfileFallback;
|
||||
|
||||
extern VipsCodedProfile vips__coded_profiles[];
|
||||
extern VipsProfileFallback *vips__profile_fallback_table[];
|
||||
|
||||
|
3
libvips/colour/profiles/Makefile.am
Normal file
3
libvips/colour/profiles/Makefile.am
Normal file
@ -0,0 +1,3 @@
|
||||
EXTRA_DIST = \
|
||||
cmyk.icm \
|
||||
sRGB.icm
|
@ -164,17 +164,10 @@ vips_rad2float_line( VipsColour *colour, VipsPel *out, VipsPel **in, int width )
|
||||
COLR *inp = (COLR *) in[0];
|
||||
COLOR *outbuf = (COLOR *) out;
|
||||
|
||||
colr_color(outbuf[0], inp[0]);
|
||||
while (--width > 0) {
|
||||
outbuf++; inp++;
|
||||
if (inp[0][RED] == inp[-1][RED] &&
|
||||
inp[0][GRN] == inp[-1][GRN] &&
|
||||
inp[0][BLU] == inp[-1][BLU] &&
|
||||
inp[0][EXP] == inp[-1][EXP])
|
||||
copycolor(outbuf[0], outbuf[-1]);
|
||||
else
|
||||
colr_color(outbuf[0], inp[0]);
|
||||
}
|
||||
int i;
|
||||
|
||||
for( i = 0; i < width; i++ )
|
||||
colr_color( outbuf[i], inp[i] );
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1,22 +1,38 @@
|
||||
#!/bin/bash
|
||||
|
||||
# code up the binary files in $1 as a set of name / base64-encoded strings
|
||||
# code up the binary files in $1 as a set of name / string pairs
|
||||
# in $2
|
||||
|
||||
# we have to use arrays for the strings, since MSVC won't allow string
|
||||
# literals larger than 64kb
|
||||
|
||||
in=$1
|
||||
out=$2
|
||||
|
||||
echo "/* coded files, generated automatically */" > $out
|
||||
echo "/* this file generated automatically, do not edit */" > $out
|
||||
echo "" >> $out
|
||||
echo "#include \"profiles.h\"" >> $out
|
||||
echo "" >> $out
|
||||
echo "VipsCodedProfile vips__coded_profiles[] = {" >> $out
|
||||
|
||||
profile_names=
|
||||
for file in $in/*; do
|
||||
root=${file%.icm}
|
||||
base=${root##*/}
|
||||
echo " { \"$base\"," >> $out
|
||||
base64 $file | sed 's/\(.*\)/"\1"/g' >> $out
|
||||
echo " }," >> $out
|
||||
profile_name=vips__profile_fallback_$base
|
||||
profile_names="$profile_names $profile_name"
|
||||
echo "static VipsProfileFallback $profile_name = {" >> $out
|
||||
echo " \"$base\"," >> $out
|
||||
echo " $(stat --format=%s $file)," >> $out
|
||||
echo " {" >> $out
|
||||
hexdump -v -e '" 0x" 1/1 "%02X,"' $file | fmt >> $out
|
||||
echo " }" >> $out
|
||||
echo "};" >> $out
|
||||
echo >> $out
|
||||
done
|
||||
echo " { 0, 0 }" >> $out
|
||||
|
||||
echo "VipsProfileFallback *vips__profile_fallback_table[] = {" >> $out
|
||||
for profile_name in $profile_names; do
|
||||
echo " &$profile_name," >> $out
|
||||
done
|
||||
echo " NULL" >> $out
|
||||
echo "};" >> $out
|
||||
|
@ -1,6 +1,7 @@
|
||||
noinst_LTLIBRARIES = libconversion.la
|
||||
|
||||
libconversion_la_SOURCES = \
|
||||
switch.c \
|
||||
transpose3d.c \
|
||||
composite.cpp \
|
||||
smartcrop.c \
|
||||
@ -44,4 +45,10 @@ libconversion_la_SOURCES = \
|
||||
subsample.c \
|
||||
zoom.c
|
||||
|
||||
AM_CPPFLAGS = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@
|
||||
# gcc annoyingly warns about clang pragmas, and does not support suppressing
|
||||
# the warning with a gcc pragma
|
||||
AM_CPPFLAGS = \
|
||||
-I${top_srcdir}/libvips/include \
|
||||
@VIPS_CFLAGS@ @VIPS_INCLUDES@ \
|
||||
-Wno-unknown-pragmas
|
||||
|
||||
|
@ -98,10 +98,6 @@ vips_autorot_get_angle( VipsImage *im )
|
||||
default:
|
||||
/* Other values do rotate + mirror, don't bother handling them
|
||||
* though, how common can mirroring be.
|
||||
*
|
||||
* See:
|
||||
*
|
||||
* http://www.80sidea.com/archives/2316
|
||||
*/
|
||||
angle = VIPS_ANGLE_D0;
|
||||
break;
|
||||
|
@ -158,6 +158,18 @@ G_DEFINE_TYPE( VipsCast, vips_cast, VIPS_TYPE_CONVERSION );
|
||||
q[x] = (p[x] << n) | (((p[x] & 1) << n) - (p[x] & 1)); \
|
||||
}
|
||||
|
||||
#define SHIFT_LEFT_SIGNED( ITYPE, OTYPE ) { \
|
||||
ITYPE * restrict p = (ITYPE *) in; \
|
||||
OTYPE * restrict q = (OTYPE *) out; \
|
||||
int n = ((int) sizeof( OTYPE ) << 3) - ((int) sizeof( ITYPE ) << 3); \
|
||||
\
|
||||
g_assert( sizeof( ITYPE ) < sizeof( OTYPE ) ); \
|
||||
\
|
||||
for( x = 0; x < sz; x++ ) \
|
||||
q[x] = VIPS_LSHIFT_INT( p[x], n ) | \
|
||||
(((p[x] & 1) << n) - (p[x] & 1)); \
|
||||
}
|
||||
|
||||
/* Cast int types to an int type. We need to pass in the type of the
|
||||
* intermediate value, either uint or int, or we'll have problems with uint
|
||||
* sources turning -ve.
|
||||
@ -188,6 +200,21 @@ G_DEFINE_TYPE( VipsCast, vips_cast, VIPS_TYPE_CONVERSION );
|
||||
} \
|
||||
}
|
||||
|
||||
/* Int to int handling for signed int types.
|
||||
*/
|
||||
#define INT_INT_SIGNED( ITYPE, OTYPE, TEMP, CAST ) { \
|
||||
if( cast->shift && \
|
||||
sizeof( ITYPE ) > sizeof( OTYPE ) ) { \
|
||||
SHIFT_RIGHT( ITYPE, OTYPE ); \
|
||||
} \
|
||||
else if( cast->shift ) { \
|
||||
SHIFT_LEFT_SIGNED( ITYPE, OTYPE ); \
|
||||
} \
|
||||
else { \
|
||||
CAST_INT_INT( ITYPE, OTYPE, TEMP, CAST ); \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Cast float types to an int type.
|
||||
*/
|
||||
#define CAST_FLOAT_INT( ITYPE, OTYPE, TEMP, CAST ) { \
|
||||
@ -336,7 +363,7 @@ vips_cast_gen( VipsRegion *or, void *vseq, void *a, void *b, gboolean *stop )
|
||||
|
||||
case VIPS_FORMAT_CHAR:
|
||||
BAND_SWITCH_INNER( signed char,
|
||||
INT_INT,
|
||||
INT_INT_SIGNED,
|
||||
CAST_REAL_FLOAT,
|
||||
CAST_REAL_COMPLEX );
|
||||
break;
|
||||
@ -350,7 +377,7 @@ vips_cast_gen( VipsRegion *or, void *vseq, void *a, void *b, gboolean *stop )
|
||||
|
||||
case VIPS_FORMAT_SHORT:
|
||||
BAND_SWITCH_INNER( signed short,
|
||||
INT_INT,
|
||||
INT_INT_SIGNED,
|
||||
CAST_REAL_FLOAT,
|
||||
CAST_REAL_COMPLEX );
|
||||
break;
|
||||
@ -364,7 +391,7 @@ vips_cast_gen( VipsRegion *or, void *vseq, void *a, void *b, gboolean *stop )
|
||||
|
||||
case VIPS_FORMAT_INT:
|
||||
BAND_SWITCH_INNER( signed int,
|
||||
INT_INT,
|
||||
INT_INT_SIGNED,
|
||||
CAST_REAL_FLOAT,
|
||||
CAST_REAL_COMPLEX );
|
||||
break;
|
||||
|
@ -1721,7 +1721,18 @@ vips_composite2( VipsImage *base, VipsImage *overlay, VipsImage **out,
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wvarargs"
|
||||
|
||||
/* Triggers a clang compiler warning because mode might not be an int.
|
||||
* I think the warning is harmless for all platforms we care about.
|
||||
*/
|
||||
va_start( ap, mode );
|
||||
|
||||
g_assert( sizeof( mode ) == sizeof( int ) );
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
result = vips_call_split( "composite2", ap, base, overlay, out, mode );
|
||||
va_end( ap );
|
||||
|
||||
|
@ -383,6 +383,7 @@ vips_conversion_operation_init( void )
|
||||
extern GType vips_rot45_get_type( void );
|
||||
extern GType vips_autorot_get_type( void );
|
||||
extern GType vips_ifthenelse_get_type( void );
|
||||
extern GType vips_switch_get_type( void );
|
||||
extern GType vips_recomb_get_type( void );
|
||||
extern GType vips_bandmean_get_type( void );
|
||||
extern GType vips_bandfold_get_type( void );
|
||||
@ -434,6 +435,7 @@ vips_conversion_operation_init( void )
|
||||
vips_rot45_get_type();
|
||||
vips_autorot_get_type();
|
||||
vips_ifthenelse_get_type();
|
||||
vips_switch_get_type();
|
||||
vips_recomb_get_type();
|
||||
vips_bandmean_get_type();
|
||||
vips_bandfold_get_type();
|
||||
|
@ -99,6 +99,25 @@ G_DEFINE_TYPE( VipsFlatten, vips_flatten, VIPS_TYPE_CONVERSION );
|
||||
} \
|
||||
}
|
||||
|
||||
/* Same, but with float arithmetic. Necessary for short/int to prevent
|
||||
* overflow.
|
||||
*/
|
||||
#define VIPS_FLATTEN_BLACK_FLOAT( TYPE ) { \
|
||||
TYPE * restrict p = (TYPE *) in; \
|
||||
TYPE * restrict q = (TYPE *) out; \
|
||||
\
|
||||
for( x = 0; x < width; x++ ) { \
|
||||
TYPE alpha = p[bands - 1]; \
|
||||
int b; \
|
||||
\
|
||||
for( b = 0; b < bands - 1; b++ ) \
|
||||
q[b] = ((double) p[b] * alpha) / max_alpha; \
|
||||
\
|
||||
p += bands; \
|
||||
q += bands - 1; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Flatten with any background.
|
||||
*/
|
||||
#define VIPS_FLATTEN( TYPE ) { \
|
||||
@ -119,25 +138,6 @@ G_DEFINE_TYPE( VipsFlatten, vips_flatten, VIPS_TYPE_CONVERSION );
|
||||
} \
|
||||
}
|
||||
|
||||
/* Same, but with float arithmetic. Necessary for int/uint to prevent
|
||||
* overflow.
|
||||
*/
|
||||
#define VIPS_FLATTEN_BLACK_FLOAT( TYPE ) { \
|
||||
TYPE * restrict p = (TYPE *) in; \
|
||||
TYPE * restrict q = (TYPE *) out; \
|
||||
\
|
||||
for( x = 0; x < width; x++ ) { \
|
||||
TYPE alpha = p[bands - 1]; \
|
||||
int b; \
|
||||
\
|
||||
for( b = 0; b < bands - 1; b++ ) \
|
||||
q[b] = ((double) p[b] * alpha) / max_alpha; \
|
||||
\
|
||||
p += bands; \
|
||||
q += bands - 1; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define VIPS_FLATTEN_FLOAT( TYPE ) { \
|
||||
TYPE * restrict p = (TYPE *) in; \
|
||||
TYPE * restrict q = (TYPE *) out; \
|
||||
@ -187,11 +187,11 @@ vips_flatten_black_gen( VipsRegion *or, void *vseq, void *a, void *b,
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_USHORT:
|
||||
VIPS_FLATTEN_BLACK( unsigned short );
|
||||
VIPS_FLATTEN_BLACK_FLOAT( unsigned short );
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_SHORT:
|
||||
VIPS_FLATTEN_BLACK( signed short );
|
||||
VIPS_FLATTEN_BLACK_FLOAT( signed short );
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_UINT:
|
||||
@ -252,11 +252,11 @@ vips_flatten_gen( VipsRegion *or, void *vseq, void *a, void *b,
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_USHORT:
|
||||
VIPS_FLATTEN( unsigned short );
|
||||
VIPS_FLATTEN_FLOAT( unsigned short );
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_SHORT:
|
||||
VIPS_FLATTEN( signed short );
|
||||
VIPS_FLATTEN_FLOAT( signed short );
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_UINT:
|
||||
|
@ -103,6 +103,10 @@ typedef struct _VipsInsert {
|
||||
VipsRect rout; /* Output space */
|
||||
VipsRect rmain; /* Position of main in output */
|
||||
VipsRect rsub; /* Position of sub in output */
|
||||
|
||||
/* TRUE if we've minimise sub.
|
||||
*/
|
||||
gboolean sub_minimised;
|
||||
} VipsInsert;
|
||||
|
||||
typedef VipsConversionClass VipsInsertClass;
|
||||
@ -164,8 +168,6 @@ vips__insert_paste_region( VipsRegion *or, VipsRegion *ir, VipsRect *pos )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Insert generate function.
|
||||
*/
|
||||
static int
|
||||
vips_insert_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
|
||||
{
|
||||
@ -175,39 +177,43 @@ vips_insert_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
|
||||
|
||||
VipsRect ovl;
|
||||
|
||||
/* Does the rect we have been asked for fall entirely inside the
|
||||
* sub-image?
|
||||
*/
|
||||
if( vips_rect_includesrect( &insert->rsub, &or->valid ) )
|
||||
return( vips__insert_just_one( or, ir[1],
|
||||
insert->rsub.left, insert->rsub.top ) );
|
||||
|
||||
/* Does it fall entirely inside the main, and not at all inside the
|
||||
* sub?
|
||||
/* The part of the subimage we will use.
|
||||
*/
|
||||
vips_rect_intersectrect( &or->valid, &insert->rsub, &ovl );
|
||||
if( vips_rect_includesrect( &insert->rmain, &or->valid ) &&
|
||||
vips_rect_isempty( &ovl ) )
|
||||
return( vips__insert_just_one( or, ir[0],
|
||||
insert->rmain.left, insert->rmain.top ) );
|
||||
|
||||
/* Output requires both (or neither) input. If it is not entirely
|
||||
* inside both the main and the sub, then there is going to be some
|
||||
* background.
|
||||
/* Three cases: we are generating entirely within the sub-image,
|
||||
* entirely within the main image, or a mixture.
|
||||
*/
|
||||
if( !(vips_rect_includesrect( &insert->rsub, &or->valid ) &&
|
||||
vips_rect_includesrect( &insert->rmain, &or->valid )) )
|
||||
vips_region_paint_pel( or, r, insert->ink );
|
||||
if( vips_rect_includesrect( &insert->rsub, &or->valid ) ) {
|
||||
if( vips__insert_just_one( or, ir[1],
|
||||
insert->rsub.left, insert->rsub.top ) )
|
||||
return( -1 );
|
||||
}
|
||||
else if( vips_rect_includesrect( &insert->rmain, &or->valid ) &&
|
||||
vips_rect_isempty( &ovl ) ) {
|
||||
if( vips__insert_just_one( or, ir[0],
|
||||
insert->rmain.left, insert->rmain.top ) )
|
||||
return( -1 );
|
||||
}
|
||||
else {
|
||||
/* Output requires both (or neither) input. If it is not
|
||||
* entirely inside both the main and the sub, then there is
|
||||
* going to be some background.
|
||||
*/
|
||||
if( !(vips_rect_includesrect( &insert->rsub, &or->valid ) &&
|
||||
vips_rect_includesrect( &insert->rmain, &or->valid )) )
|
||||
vips_region_paint_pel( or, r, insert->ink );
|
||||
|
||||
/* Paste from main.
|
||||
*/
|
||||
if( vips__insert_paste_region( or, ir[0], &insert->rmain ) )
|
||||
return( -1 );
|
||||
/* Paste from main.
|
||||
*/
|
||||
if( vips__insert_paste_region( or, ir[0], &insert->rmain ) )
|
||||
return( -1 );
|
||||
|
||||
/* Paste from sub.
|
||||
*/
|
||||
if( vips__insert_paste_region( or, ir[1], &insert->rsub ) )
|
||||
return( -1 );
|
||||
/* Paste from sub.
|
||||
*/
|
||||
if( vips__insert_paste_region( or, ir[1], &insert->rsub ) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
@ -171,7 +171,8 @@ vips_sequential_generate( VipsRegion *or,
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
sequential->y_pos = VIPS_MAX( sequential->y_pos, VIPS_RECT_BOTTOM( r ) );
|
||||
sequential->y_pos =
|
||||
VIPS_MAX( sequential->y_pos, VIPS_RECT_BOTTOM( r ) );
|
||||
|
||||
g_mutex_unlock( sequential->lock );
|
||||
|
||||
@ -194,6 +195,11 @@ vips_sequential_build( VipsObject *object )
|
||||
if( vips_linecache( sequential->in, &t,
|
||||
"tile_height", sequential->tile_height,
|
||||
"access", VIPS_ACCESS_SEQUENTIAL,
|
||||
/* We need seq caches to persist across minimise in case
|
||||
* someone is trying to read an image with a series of crop
|
||||
* operations.
|
||||
*/
|
||||
"persistent", TRUE,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
|
||||
|
260
libvips/conversion/switch.c
Normal file
260
libvips/conversion/switch.c
Normal file
@ -0,0 +1,260 @@
|
||||
/* switch between an array of images
|
||||
*
|
||||
* 28/7/19
|
||||
* - from maplut.c
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
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
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/internal.h>
|
||||
|
||||
typedef struct _VipsSwitch {
|
||||
VipsOperation parent_instance;
|
||||
|
||||
VipsArrayImage *tests;
|
||||
VipsImage *out;
|
||||
|
||||
int n;
|
||||
|
||||
} VipsSwitch;
|
||||
|
||||
typedef VipsOperationClass VipsSwitchClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsSwitch, vips_switch, VIPS_TYPE_OPERATION );
|
||||
|
||||
static int
|
||||
vips_switch_gen( VipsRegion *or, void *seq, void *a, void *b,
|
||||
gboolean *stop )
|
||||
{
|
||||
VipsRegion **ar = (VipsRegion **) seq;
|
||||
VipsSwitch *swit = (VipsSwitch *) b;
|
||||
VipsRect *r = &or->valid;
|
||||
|
||||
int x, y, i;
|
||||
VipsPel * restrict q;
|
||||
size_t qls;
|
||||
VipsPel * restrict p[256];
|
||||
size_t ls[256];
|
||||
|
||||
if( vips_reorder_prepare_many( or->im, ar, r ) )
|
||||
return( -1 );
|
||||
|
||||
g_assert( ar[0]->im->BandFmt == VIPS_FORMAT_UCHAR );
|
||||
g_assert( ar[0]->im->Bands == 1 );
|
||||
|
||||
for( i = 0; i < swit->n; i++ ) {
|
||||
p[i] = VIPS_REGION_ADDR( ar[i], r->left, r->top );
|
||||
ls[i] = VIPS_REGION_LSKIP( ar[i] );
|
||||
}
|
||||
|
||||
q = VIPS_REGION_ADDR( or, r->left, r->top );
|
||||
qls = VIPS_REGION_LSKIP( or );
|
||||
for( y = 0; y < r->height; y++ ) {
|
||||
for( x = 0; x < r->width; x++ ) {
|
||||
for( i = 0; i < swit->n; i++ )
|
||||
if( p[i][x] )
|
||||
break;
|
||||
|
||||
q[x] = i;
|
||||
}
|
||||
|
||||
q += qls;
|
||||
for( i = 0; i < swit->n; i++ )
|
||||
p[i] += ls[i];
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_switch_build( VipsObject *object )
|
||||
{
|
||||
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
|
||||
VipsSwitch *swit = (VipsSwitch *) object;
|
||||
|
||||
VipsImage **tests;
|
||||
VipsImage **decode;
|
||||
VipsImage **format;
|
||||
VipsImage **band;
|
||||
VipsImage **size;
|
||||
int i;
|
||||
|
||||
g_object_set( object, "out", vips_image_new(), NULL );
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_switch_parent_class )->build( object ) )
|
||||
return( -1 );
|
||||
|
||||
/* 255 rather than 256, since we want to reserve +1 as the no
|
||||
* match value.
|
||||
*/
|
||||
tests = vips_area_get_data( &swit->tests->area,
|
||||
NULL, &swit->n, NULL, NULL );
|
||||
if( swit->n > 255 ||
|
||||
swit->n < 1 ) {
|
||||
vips_error( class->nickname, "%s", _( "bad number of tests" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
decode = (VipsImage **) vips_object_local_array( object, swit->n );
|
||||
format = (VipsImage **) vips_object_local_array( object, swit->n );
|
||||
band = (VipsImage **) vips_object_local_array( object, swit->n + 1 );
|
||||
size = (VipsImage **) vips_object_local_array( object, swit->n + 1 );
|
||||
|
||||
/* Decode RAD/LABQ etc.
|
||||
*/
|
||||
for( i = 0; i < swit->n; i++ )
|
||||
if( vips_image_decode( tests[i], &decode[i] ) )
|
||||
return( -1 );
|
||||
tests = decode;
|
||||
|
||||
/* Must be uchar.
|
||||
*/
|
||||
for( i = 0; i < swit->n; i++ )
|
||||
if( vips_cast_uchar( tests[i], &format[i], NULL ) )
|
||||
return( -1 );
|
||||
tests = format;
|
||||
|
||||
/* Images must match in size and bands.
|
||||
*/
|
||||
if( vips__bandalike_vec( class->nickname, tests, band, swit->n, 1 ) ||
|
||||
vips__sizealike_vec( band, size, swit->n ) )
|
||||
return( -1 );
|
||||
tests = size;
|
||||
|
||||
if( tests[0]->Bands > 1 ) {
|
||||
vips_error( class->nickname,
|
||||
"%s", _( "test images not 1-band" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( vips_image_pipeline_array( swit->out,
|
||||
VIPS_DEMAND_STYLE_THINSTRIP, tests ) )
|
||||
return( -1 );
|
||||
|
||||
if( vips_image_generate( swit->out,
|
||||
vips_start_many, vips_switch_gen, vips_stop_many,
|
||||
tests, swit ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_switch_class_init( VipsSwitchClass *class )
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( class );
|
||||
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
|
||||
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
object_class->nickname = "switch";
|
||||
object_class->description =
|
||||
_( "find the index of the first non-zero pixel in tests" );
|
||||
object_class->build = vips_switch_build;
|
||||
|
||||
operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
|
||||
|
||||
VIPS_ARG_BOXED( class, "tests", 1,
|
||||
_( "Tests" ),
|
||||
_( "Table of images to test" ),
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
G_STRUCT_OFFSET( VipsSwitch, tests ),
|
||||
VIPS_TYPE_ARRAY_IMAGE );
|
||||
|
||||
VIPS_ARG_IMAGE( class, "out", 2,
|
||||
_( "Output" ),
|
||||
_( "Output image" ),
|
||||
VIPS_ARGUMENT_REQUIRED_OUTPUT,
|
||||
G_STRUCT_OFFSET( VipsSwitch, out ) );
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
vips_switch_init( VipsSwitch *swit )
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
vips_switchv( VipsImage **tests, VipsImage **out, int n, va_list ap )
|
||||
{
|
||||
VipsArrayImage *tests_array;
|
||||
int result;
|
||||
|
||||
tests_array = vips_array_image_new( tests, n );
|
||||
result = vips_call_split( "switch", ap, tests_array, out );
|
||||
vips_area_unref( VIPS_AREA( tests_array ) );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_switch: (method)
|
||||
* @tests: (array length=n): test these images
|
||||
* @out: (out): output index image
|
||||
* @n: number of input images
|
||||
* @...: %NULL-terminated list of optional named arguments
|
||||
*
|
||||
* The @tests images are evaluated and at each point the index of the first
|
||||
* non-zero value is written to @out. If all @tests are false, the value
|
||||
* (@n + 1) is written.
|
||||
*
|
||||
* Images in @tests must have one band. They are expanded to the
|
||||
* bounding box of the set of images in @tests, and that size is used for
|
||||
* @out. @tests can have up to 255 elements.
|
||||
*
|
||||
* Combine with vips_case() to make an efficient multi-way vips_ifthenelse().
|
||||
*
|
||||
* See also: vips_maplut(), vips_case(), vips_ifthenelse().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
vips_switch( VipsImage **tests, VipsImage **out, int n, ... )
|
||||
{
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
va_start( ap, n );
|
||||
result = vips_switchv( tests, out, n, ap );
|
||||
va_end( ap );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
@ -418,7 +418,7 @@ vips_rect_hash( VipsRect *pos )
|
||||
* X discrimination is more important than Y, since
|
||||
* most tiles will have a similar Y.
|
||||
*/
|
||||
hash = pos->left ^ (pos->top << 16);
|
||||
hash = (guint) pos->left ^ ((guint) pos->top << 16);
|
||||
|
||||
return( hash );
|
||||
}
|
||||
|
@ -62,6 +62,7 @@ typedef struct _VipsUnpremultiply {
|
||||
VipsImage *in;
|
||||
|
||||
double max_alpha;
|
||||
int alpha_band;
|
||||
|
||||
} VipsUnpremultiply;
|
||||
|
||||
@ -76,17 +77,21 @@ G_DEFINE_TYPE( VipsUnpremultiply, vips_unpremultiply, VIPS_TYPE_CONVERSION );
|
||||
OUT * restrict q = (OUT *) out; \
|
||||
\
|
||||
for( x = 0; x < width; x++ ) { \
|
||||
IN alpha = p[bands - 1]; \
|
||||
IN alpha = p[alpha_band]; \
|
||||
IN clip_alpha = VIPS_CLIP( 0, alpha, max_alpha ); \
|
||||
OUT nalpha = (OUT) clip_alpha / max_alpha; \
|
||||
\
|
||||
if( clip_alpha == 0 ) \
|
||||
for( i = 0; i < bands - 1; i++ ) \
|
||||
if( nalpha == 0 ) \
|
||||
for( i = 0; i < alpha_band + 1; i++ ) \
|
||||
q[i] = 0; \
|
||||
else \
|
||||
for( i = 0; i < bands - 1; i++ ) \
|
||||
else { \
|
||||
for( i = 0; i < alpha_band; i++ ) \
|
||||
q[i] = p[i] / nalpha; \
|
||||
q[i] = clip_alpha; \
|
||||
q[alpha_band] = clip_alpha; \
|
||||
} \
|
||||
\
|
||||
for( i = alpha_band + 1; i < bands; i++ ) \
|
||||
q[i] = p[i]; \
|
||||
\
|
||||
p += bands; \
|
||||
q += bands; \
|
||||
@ -104,17 +109,18 @@ G_DEFINE_TYPE( VipsUnpremultiply, vips_unpremultiply, VIPS_TYPE_CONVERSION );
|
||||
IN clip_alpha = VIPS_CLIP( 0, alpha, max_alpha ); \
|
||||
OUT nalpha = (OUT) clip_alpha / max_alpha; \
|
||||
\
|
||||
if( clip_alpha == 0 ) { \
|
||||
if( nalpha == 0 ) { \
|
||||
q[0] = 0; \
|
||||
q[1] = 0; \
|
||||
q[2] = 0; \
|
||||
q[3] = 0; \
|
||||
} \
|
||||
else { \
|
||||
q[0] = p[0] / nalpha; \
|
||||
q[1] = p[1] / nalpha; \
|
||||
q[2] = p[2] / nalpha; \
|
||||
q[3] = clip_alpha; \
|
||||
} \
|
||||
q[3] = clip_alpha; \
|
||||
\
|
||||
p += 4; \
|
||||
q += 4; \
|
||||
@ -141,6 +147,7 @@ vips_unpremultiply_gen( VipsRegion *or, void *vseq, void *a, void *b,
|
||||
int width = r->width;
|
||||
int bands = im->Bands;
|
||||
double max_alpha = unpremultiply->max_alpha;
|
||||
int alpha_band = unpremultiply->alpha_band;
|
||||
|
||||
int x, y, i;
|
||||
|
||||
@ -235,6 +242,11 @@ vips_unpremultiply_build( VipsObject *object )
|
||||
in->Type == VIPS_INTERPRETATION_RGB16 )
|
||||
unpremultiply->max_alpha = 65535;
|
||||
|
||||
/* Is alpha-band unset? Default to the final band for this image.
|
||||
*/
|
||||
if( !vips_object_argument_isset( object, "alpha_band" ) )
|
||||
unpremultiply->alpha_band = in->Bands - 1;
|
||||
|
||||
if( in->BandFmt == VIPS_FORMAT_DOUBLE )
|
||||
conversion->out->BandFmt = VIPS_FORMAT_DOUBLE;
|
||||
else
|
||||
@ -279,6 +291,13 @@ vips_unpremultiply_class_init( VipsUnpremultiplyClass *class )
|
||||
G_STRUCT_OFFSET( VipsUnpremultiply, max_alpha ),
|
||||
0, 100000000, 255 );
|
||||
|
||||
VIPS_ARG_INT( class, "alpha_band", 116,
|
||||
_( "Alpha band" ),
|
||||
_( "Unpremultiply with this alpha" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsUnpremultiply, alpha_band ),
|
||||
0, 100000000, 3 );
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
@ -296,10 +315,11 @@ vips_unpremultiply_init( VipsUnpremultiply *unpremultiply )
|
||||
* Optional arguments:
|
||||
*
|
||||
* * @max_alpha: %gdouble, maximum value for alpha
|
||||
* * @alpha_band: %gint, band containing alpha data
|
||||
*
|
||||
* Unpremultiplies any alpha channel.
|
||||
* The final band is taken to be the alpha
|
||||
* and the bands are transformed as:
|
||||
* Band @alpha_band (by default the final band) contains the alpha and all
|
||||
* other bands are transformed as:
|
||||
*
|
||||
* |[
|
||||
* alpha = (int) clip( 0, in[in.bands - 1], @max_alpha );
|
||||
@ -312,8 +332,7 @@ vips_unpremultiply_init( VipsUnpremultiply *unpremultiply )
|
||||
*
|
||||
* So for an N-band image, the first N - 1 bands are divided by the clipped
|
||||
* and normalised final band, the final band is clipped.
|
||||
* If there is only a single band,
|
||||
* the image is passed through unaltered.
|
||||
* If there is only a single band, the image is passed through unaltered.
|
||||
*
|
||||
* The result is
|
||||
* #VIPS_FORMAT_FLOAT unless the input format is #VIPS_FORMAT_DOUBLE, in which
|
||||
|
@ -123,6 +123,7 @@
|
||||
#include <limits.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/internal.h>
|
||||
|
||||
#include "pconvolution.h"
|
||||
|
||||
@ -979,7 +980,7 @@ vips_convi_intize( VipsConvi *convi, VipsImage *M )
|
||||
if( convi->exp > 0 )
|
||||
int_value = (int_sum + (1 << (convi->exp - 1))) >> convi->exp;
|
||||
else
|
||||
int_value = int_sum << convi->exp;
|
||||
int_value = VIPS_LSHIFT_INT( int_sum, convi->exp );
|
||||
int_value = VIPS_CLIP( 0, int_value, 255 );
|
||||
|
||||
if( VIPS_ABS( true_value - int_value ) > 2 ) {
|
||||
|
@ -64,7 +64,7 @@ vips_convsep_build( VipsObject *object )
|
||||
VipsConvolution *convolution = (VipsConvolution *) object;
|
||||
VipsConvsep *convsep = (VipsConvsep *) object;
|
||||
VipsImage **t = (VipsImage **)
|
||||
vips_object_local_array( object, 3 );
|
||||
vips_object_local_array( object, 4 );
|
||||
|
||||
VipsImage *in;
|
||||
|
||||
@ -86,19 +86,19 @@ vips_convsep_build( VipsObject *object )
|
||||
in = t[0];
|
||||
}
|
||||
else {
|
||||
if( vips_rot( convolution->M, &t[0], VIPS_ANGLE_D90, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
/* We must only add the offset once.
|
||||
/* Take a copy, since we must set the offset.
|
||||
*/
|
||||
vips_image_set_double( t[0], "offset", 0 );
|
||||
if( vips_rot( convolution->M, &t[0], VIPS_ANGLE_D90, NULL ) ||
|
||||
vips_copy( t[0], &t[3], NULL ) )
|
||||
return( -1 );
|
||||
vips_image_set_double( t[3], "offset", 0 );
|
||||
|
||||
if( vips_conv( in, &t[1], convolution->M,
|
||||
"precision", convsep->precision,
|
||||
"layers", convsep->layers,
|
||||
"cluster", convsep->cluster,
|
||||
NULL ) ||
|
||||
vips_conv( t[1], &t[2], t[0],
|
||||
vips_conv( t[1], &t[2], t[3],
|
||||
"precision", convsep->precision,
|
||||
"layers", convsep->layers,
|
||||
"cluster", convsep->cluster,
|
||||
|
@ -39,6 +39,8 @@
|
||||
* - swap "radius" for "sigma", allows finer control
|
||||
* - allow a much greater range of parameters
|
||||
* - move to defaults suitable for screen output
|
||||
* 28/8/19
|
||||
* - fix sigma 0.5 case (thanks 2h4dl)
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -170,10 +172,11 @@ vips_sharpen_build( VipsObject *object )
|
||||
{
|
||||
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
|
||||
VipsSharpen *sharpen = (VipsSharpen *) object;
|
||||
VipsImage **t = (VipsImage **) vips_object_local_array( object, 7 );
|
||||
VipsImage **t = (VipsImage **) vips_object_local_array( object, 8 );
|
||||
VipsImage **args = (VipsImage **) vips_object_local_array( object, 2 );
|
||||
|
||||
VipsImage *in;
|
||||
VipsInterpretation old_interpretation;
|
||||
int i;
|
||||
|
||||
VIPS_GATE_START( "vips_sharpen_build: build" );
|
||||
@ -190,6 +193,7 @@ vips_sharpen_build( VipsObject *object )
|
||||
|
||||
in = sharpen->in;
|
||||
|
||||
old_interpretation = in->Type;
|
||||
if( vips_colourspace( in, &t[0], VIPS_INTERPRETATION_LABS, NULL ) )
|
||||
return( -1 );
|
||||
in = t[0];
|
||||
@ -199,10 +203,10 @@ vips_sharpen_build( VipsObject *object )
|
||||
vips_check_format( class->nickname, in, VIPS_FORMAT_SHORT ) )
|
||||
return( -1 );
|
||||
|
||||
/* Stop at 20% of max ... a bit mean. We always sharpen a short,
|
||||
/* Stop at 10% of max ... a bit mean. We always sharpen a short,
|
||||
* so there's no point using a float mask.
|
||||
*/
|
||||
if( vips_gaussmat( &t[1], sharpen->sigma, 0.2,
|
||||
if( vips_gaussmat( &t[1], sharpen->sigma, 0.1,
|
||||
"separable", TRUE,
|
||||
"precision", VIPS_PRECISION_INTEGER,
|
||||
NULL ) )
|
||||
@ -269,9 +273,6 @@ vips_sharpen_build( VipsObject *object )
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
|
||||
/* Set demand hints. FATSTRIP is good for us, as THINSTRIP will cause
|
||||
* too many recalculations on overlaps.
|
||||
*/
|
||||
t[5] = vips_image_new();
|
||||
if( vips_image_pipeline_array( t[5],
|
||||
VIPS_DEMAND_STYLE_FATSTRIP, args ) )
|
||||
@ -287,7 +288,8 @@ vips_sharpen_build( VipsObject *object )
|
||||
/* Reattach the rest.
|
||||
*/
|
||||
if( vips_bandjoin2( t[5], t[3], &t[6], NULL ) ||
|
||||
vips_image_write( t[6], sharpen->out ) )
|
||||
vips_colourspace( t[6], &t[7], old_interpretation, NULL ) ||
|
||||
vips_image_write( t[7], sharpen->out ) )
|
||||
return( -1 );
|
||||
|
||||
VIPS_GATE_STOP( "vips_sharpen_build: build" );
|
||||
|
@ -64,9 +64,12 @@ vips_mask_butterworth_point( VipsMask *mask, double dx, double dy )
|
||||
|
||||
double cnst = (1.0 / ac) - 1.0;
|
||||
double fc2 = fc * fc;
|
||||
double dist2 = fc2 / (dx * dx + dy * dy);
|
||||
double d = dx * dx + dy * dy;
|
||||
|
||||
return( 1.0 / (1.0 + cnst * pow( dist2, order )) );
|
||||
if( d == 0 )
|
||||
return( 0 );
|
||||
else
|
||||
return( 1.0 / (1.0 + cnst * pow( fc2 / d, order )) );
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -239,6 +239,7 @@ vips_text_autofit( VipsText *text )
|
||||
target.width = text->width;
|
||||
target.height = text->height;
|
||||
previous_dpi = -1;
|
||||
previous_difference = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips_text_autofit: "
|
||||
|
@ -111,9 +111,18 @@ jpeg2vips( const char *name, IMAGE *out, gboolean header_only )
|
||||
}
|
||||
|
||||
#ifdef HAVE_JPEG
|
||||
if( vips__jpeg_read_file( filename, out,
|
||||
header_only, shrink, fail_on_warn, FALSE ) )
|
||||
{
|
||||
VipsStreami *streami;
|
||||
|
||||
if( !(streami = vips_streami_new_from_file( filename )) )
|
||||
return( -1 );
|
||||
if( vips__jpeg_read_stream( streami, out,
|
||||
header_only, shrink, fail_on_warn, FALSE ) ) {
|
||||
VIPS_UNREF( streami );
|
||||
return( -1 );
|
||||
}
|
||||
VIPS_UNREF( streami );
|
||||
}
|
||||
#else
|
||||
vips_error( "im_jpeg2vips",
|
||||
"%s", _( "no JPEG support in your libvips" ) );
|
||||
|
@ -83,14 +83,21 @@ png2vips( const char *name, IMAGE *out, gboolean header_only )
|
||||
}
|
||||
|
||||
#ifdef HAVE_PNG
|
||||
if( header_only ) {
|
||||
if( vips__png_header( filename, out ) )
|
||||
return( -1 );
|
||||
}
|
||||
else {
|
||||
if( vips__png_read( filename, out, TRUE ) )
|
||||
return( -1 );
|
||||
}
|
||||
{
|
||||
VipsStreami *streami;
|
||||
int result;
|
||||
|
||||
if( !(streami = vips_streami_new_from_file( filename )) )
|
||||
return( -1 );
|
||||
if( header_only )
|
||||
result = vips__png_header_stream( streami, out );
|
||||
else
|
||||
result = vips__png_read_stream( streami, out, TRUE );
|
||||
VIPS_UNREF( streami );
|
||||
|
||||
if( result )
|
||||
return( result );
|
||||
}
|
||||
#else
|
||||
vips_error( "im_png2vips",
|
||||
"%s", _( "no PNG support in your libvips" ) );
|
||||
|
@ -52,6 +52,57 @@
|
||||
|
||||
#include "../foreign/pforeign.h"
|
||||
|
||||
#ifdef HAVE_TIFF
|
||||
static gboolean
|
||||
im_istifftiled( const char *filename )
|
||||
{
|
||||
VipsStreami *streami;
|
||||
gboolean result;
|
||||
|
||||
if( !(streami = vips_streami_new_from_file( filename )) )
|
||||
return( FALSE );
|
||||
result = vips__istiff_stream( streami );
|
||||
VIPS_UNREF( streami );
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
static int
|
||||
im_tiff_read_header( const char *filename, VipsImage *out,
|
||||
int page, int n, gboolean autorotate )
|
||||
{
|
||||
VipsStreami *streami;
|
||||
|
||||
if( !(streami = vips_streami_new_from_file( filename )) )
|
||||
return( -1 );
|
||||
if( vips__tiff_read_header_stream( streami,
|
||||
out, page, n, autorotate ) ) {
|
||||
VIPS_UNREF( streami );
|
||||
return( -1 );
|
||||
}
|
||||
VIPS_UNREF( streami );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
im_tiff_read( const char *filename, VipsImage *out,
|
||||
int page, int n, gboolean autorotate )
|
||||
{
|
||||
VipsStreami *streami;
|
||||
|
||||
if( !(streami = vips_streami_new_from_file( filename )) )
|
||||
return( -1 );
|
||||
if( vips__tiff_read_stream( streami, out, page, n, autorotate ) ) {
|
||||
VIPS_UNREF( streami );
|
||||
return( -1 );
|
||||
}
|
||||
VIPS_UNREF( streami );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
#endif /*HAVE_TIFF*/
|
||||
|
||||
static int
|
||||
tiff2vips( const char *name, IMAGE *out, gboolean header_only )
|
||||
{
|
||||
@ -88,18 +139,18 @@ tiff2vips( const char *name, IMAGE *out, gboolean header_only )
|
||||
|
||||
if( !header_only &&
|
||||
!seq &&
|
||||
!vips__istifftiled( filename ) &&
|
||||
!im_istifftiled( filename ) &&
|
||||
out->dtype == VIPS_IMAGE_PARTIAL ) {
|
||||
if( vips__image_wio_output( out ) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( header_only ) {
|
||||
if( vips__tiff_read_header( filename, out, page, 1, FALSE ) )
|
||||
if( im_tiff_read_header( filename, out, page, 1, FALSE ) )
|
||||
return( -1 );
|
||||
}
|
||||
else {
|
||||
if( vips__tiff_read( filename, out, page, 1, FALSE ) )
|
||||
if( im_tiff_read( filename, out, page, 1, FALSE ) )
|
||||
return( -1 );
|
||||
}
|
||||
#else
|
||||
|
@ -75,6 +75,8 @@ im_vips2dz( IMAGE *in, const char *filename )
|
||||
*p = '\0';
|
||||
im_strncpy( mode, p + 1, FILENAME_MAX );
|
||||
}
|
||||
else
|
||||
strcpy( mode, "" );
|
||||
|
||||
strcpy( buf, mode );
|
||||
p = &buf[0];
|
||||
|
@ -51,14 +51,21 @@ webp2vips( const char *name, IMAGE *out, gboolean header_only )
|
||||
im_filename_split( name, filename, mode );
|
||||
|
||||
#ifdef HAVE_LIBWEBP
|
||||
if( header_only ) {
|
||||
if( vips__webp_read_file_header( filename, out, 0, 1, 1 ) )
|
||||
return( -1 );
|
||||
}
|
||||
else {
|
||||
if( vips__webp_read_file( filename, out, 0, 1, 1 ) )
|
||||
return( -1 );
|
||||
}
|
||||
{
|
||||
VipsStreami *streami;
|
||||
int result;
|
||||
|
||||
if( !(streami = vips_streami_new_from_file( filename )) )
|
||||
return( -1 );
|
||||
if( header_only )
|
||||
result = vips__webp_read_header_stream( streami, out, 0, 1, 1 );
|
||||
else
|
||||
result = vips__webp_read_stream( streami, out, 0, 1, 1 );
|
||||
VIPS_UNREF( streami );
|
||||
|
||||
if( result )
|
||||
return( result );
|
||||
}
|
||||
#else
|
||||
vips_error( "im_webp2vips",
|
||||
"%s", _( "no webp support in your libvips" ) );
|
||||
@ -69,6 +76,25 @@ webp2vips( const char *name, IMAGE *out, gboolean header_only )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static gboolean
|
||||
vips__iswebp( const char *filename )
|
||||
{
|
||||
gboolean result;
|
||||
|
||||
#ifdef HAVE_LIBWEBP
|
||||
VipsStreami *streami;
|
||||
|
||||
if( !(streami = vips_streami_new_from_file( filename )) )
|
||||
return( FALSE );
|
||||
result = vips__png_ispng_stream( streami );
|
||||
VIPS_UNREF( streami );
|
||||
#else /*!HAVE_LIBWEBP*/
|
||||
result = -1;
|
||||
#endif /*HAVE_LIBWEBP*/
|
||||
|
||||
return( result );
|
||||
}
|
||||
|
||||
int
|
||||
im_webp2vips( const char *name, IMAGE *out )
|
||||
{
|
||||
|
@ -297,7 +297,6 @@ flood_scanline( Flood *flood, int x, int y, int *x1, int *x2 )
|
||||
{
|
||||
const int width = flood->test->Xsize;
|
||||
|
||||
VipsPel *p;
|
||||
int i;
|
||||
|
||||
g_assert( flood_connected( flood,
|
||||
@ -309,23 +308,33 @@ flood_scanline( Flood *flood, int x, int y, int *x1, int *x2 )
|
||||
* pixel is unpainted, we know all the intervening pixels must be
|
||||
* unpainted too.
|
||||
*/
|
||||
p = VIPS_IMAGE_ADDR( flood->test, x + 1, y );
|
||||
for( i = x + 1; i < width; i++ ) {
|
||||
if( !flood_connected( flood, p ) )
|
||||
break;
|
||||
p += flood->tsize;
|
||||
if( x < width ) {
|
||||
VipsPel *p = VIPS_IMAGE_ADDR( flood->test, x + 1, y );
|
||||
|
||||
for( i = x + 1; i < width; i++ ) {
|
||||
if( !flood_connected( flood, p ) )
|
||||
break;
|
||||
p += flood->tsize;
|
||||
}
|
||||
*x2 = i - 1;
|
||||
}
|
||||
*x2 = i - 1;
|
||||
else
|
||||
*x2 = width;
|
||||
|
||||
/* Search left.
|
||||
*/
|
||||
p = VIPS_IMAGE_ADDR( flood->test, x - 1, y );
|
||||
for( i = x - 1; i >= 0; i-- ) {
|
||||
if( !flood_connected( flood, p ) )
|
||||
break;
|
||||
p -= flood->tsize;
|
||||
if( x > 0 ) {
|
||||
VipsPel *p = VIPS_IMAGE_ADDR( flood->test, x - 1, y );
|
||||
|
||||
for( i = x - 1; i >= 0; i-- ) {
|
||||
if( !flood_connected( flood, p ) )
|
||||
break;
|
||||
p -= flood->tsize;
|
||||
}
|
||||
*x1 = i + 1;
|
||||
}
|
||||
*x1 = i + 1;
|
||||
else
|
||||
*x1 = 0;
|
||||
|
||||
/* Paint the range we discovered.
|
||||
*/
|
||||
|
@ -16,7 +16,6 @@ libforeign_la_SOURCES = \
|
||||
radiance.c \
|
||||
radload.c \
|
||||
radsave.c \
|
||||
ppm.c \
|
||||
ppmload.c \
|
||||
ppmsave.c \
|
||||
csv.c \
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user