Merge branch 'master' into improve-detection-of-bad-profiles

This commit is contained in:
John Cupitt 2021-04-24 18:29:22 +01:00
commit 6a0e5c26db
81 changed files with 7634 additions and 2575 deletions

View File

@ -56,19 +56,15 @@ jobs:
liblcms2-dev libpoppler-glib-dev librsvg2-dev
libgif-dev libopenexr-dev libpango1.0-dev
libgsf-1-dev libopenslide-dev libffi-dev
libopenjp2-7-dev
- name: Install macOS dependencies
if: contains(matrix.os, 'macos')
run:
brew install
autoconf automake libtool
gtk-doc gobject-introspection
cfitsio fftw giflib
glib libexif libgsf
libheif libjpeg-turbo libmatio
librsvg libspng libtiff
little-cms2 openexr openslide
orc pango poppler webp
run: |
brew update
brew upgrade
brew install autoconf automake libtool fftw fontconfig gtk-doc gobject-introspection glib libexif libgsf little-cms2 orc pango
brew install cfitsio imagemagick@6 libheif libjpeg-turbo libmatio librsvg libspng libtiff openexr openjpeg openslide poppler webp
- name: Install Clang 10
env:
@ -93,7 +89,7 @@ jobs:
if: contains(matrix.os, 'macos')
run: |
echo "JOBS=$(sysctl -n hw.logicalcpu)" >> $GITHUB_ENV
echo "PKG_CONFIG_PATH=/usr/local/opt/jpeg-turbo/lib/pkgconfig:/usr/local/opt/libxml2/lib/pkgconfig" >> $GITHUB_ENV
echo "PKG_CONFIG_PATH=/usr/local/opt/jpeg-turbo/lib/pkgconfig:/usr/local/opt/libxml2/lib/pkgconfig:/usr/local/opt/imagemagick@6/lib/pkgconfig" >> $GITHUB_ENV
- name: Prepare sanitizers
if: matrix.sanitize

1
.gitignore vendored
View File

@ -41,6 +41,7 @@ Vips-8.0.typelib
*.pyc
*.pyo
.deps
.dirstamp
.libs
aclocal.m4
config.log

View File

@ -23,4 +23,6 @@ Nicolas Robidoux contributed optimized bilinear and bicubic code to
the VipsInterpolate class and, with Chantal Racette and Adam Turcotte,
contributed the novel LBB, Nohalo and VSQBS interpolators.
Lovell Fuller and Kleis Auke Wolthuizen made many contributions and fixes.
Many other active contributors, see https://github.com/libvips/libvips/graphs/contributors

View File

@ -20,19 +20,24 @@
- add vips_fitsload_source(), vips_niftiload_source()
- png and gif load note background colour as metadata [781545872]
- add vips_image_[set|get]_array_double()
- add GIF load with libnsgif
- add JPEG2000 load and save
- add black_point_compensation flag for icc transforms
- add "rgba" flag to vips_text() to enable full colour text rendering
22/12/20 start 8.10.6
- don't seek on bad file descriptors [kleisauke]
- check for null memory sources [kleisauke]
- revise ppmload, fixing a couple of small bugs
- signal error on EOF in jpegload more reliably [bozaro]
- better error detection in spngload [randy408]
- improve ppmload, fixing a couple of small bugs
- improve EOF detection in jpegload [bozaro]
- improve error detection in spngload [randy408]
- fix includes of glib headers in C++ [lovell]
- fix build with more modern librsvg [lovell]
- fix a possible segv with very wide images [f1ac]
- revise premultiply, again [jjonesrs]
- revise profile handling in vipsthumbnail
- fix issue thumbnailing RGBA images in linear mode [jjonesrs]
- improve vipsthumbnail profile handling
- fix tiff deflate predictor setting [Adios]
- fix vector path for composite on i386 [kleisauke]
18/12/20 started 8.10.5
- fix potential /0 in animated webp load [lovell]

View File

@ -22,7 +22,7 @@ operations, frequency filtering, colour, resampling,
statistics and others. It supports a large range of [numeric
types](https://libvips.github.io/libvips/API/current/VipsImage.html#VipsBandFormat),
from 8-bit int to 128-bit complex. Images can have any number of bands.
It supports a good range of image formats, including JPEG, TIFF, PNG,
It supports a good range of image formats, including JPEG, JPEG2000, TIFF, PNG,
WebP, HEIC, AVIF, FITS, Matlab, OpenEXR, PDF, SVG, HDR, PPM / PGM / PFM,
CSV, GIF, Analyze, NIfTI, DeepZoom, and OpenSlide. It can also load images
via ImageMagick or GraphicsMagick, letting it work with formats like DICOM.
@ -116,6 +116,13 @@ Debug build:
make
make install
# Built-in loaders
libvips has a number of built-in loaders and savers. You can disable these if
you wish, for example:
./configure --prefix=/Users/john/vips --without-nsgif --without-ppm
# Dependencies
libvips has to have `libglib2.0-dev` and `libexpat1-dev`. Other dependencies
@ -128,14 +135,14 @@ 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.
Libraries like giflib and nifti do not use `pkg-config` so libvips will also
Libraries like 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-nifti-includes=/opt/local/include \
--with-nifti-libraries=/opt/local/lib
or perhaps:
@ -151,11 +158,6 @@ The IJG JPEG library. Use the `-turbo` version if you can.
If available, libvips adds support for EXIF metadata in JPEG files.
### giflib
The standard gif loader. If this is not present, vips will try to load gifs
via imagemagick instead.
### librsvg
The usual SVG loader. If this is not present, vips will try to load SVGs
@ -241,10 +243,10 @@ If you are going to be using libvips with untrusted images, perhaps in a
web server, for example, you should consider the security implications of
enabling a package with such a large attack surface.
### pangoft2
### pangocairo
If available, libvips adds support for text rendering. You need the
package pangoft2 in `pkg-config --list-all`.
package pangocairo in `pkg-config --list-all`.
### orc-0.4
@ -272,6 +274,10 @@ If available, vips can load and save NIfTI images.
If available, libvips will directly read (but not write, sadly)
OpenEXR images.
### OpenJPEG
If available, libvips will read and write JPEG2000 images.
### OpenSlide
If available, libvips can load OpenSlide-supported virtual slide

View File

@ -26,7 +26,12 @@ VIPS_MAJOR_VERSION=vips_major_version()
VIPS_MINOR_VERSION=vips_minor_version()
VIPS_MICRO_VERSION=vips_micro_version()
VIPS_VERSION=vips_version()
VIPS_VERSION_STRING=$VIPS_VERSION-`date -u -r $srcdir/ChangeLog`
VIPS_VERSION_STRING="$VIPS_VERSION-$(date -u -r $srcdir/ChangeLog)"
# packages add to these as we find them
VIPS_CFLAGS=""
VIPS_INCLUDES=""
VIPS_LIBS=""
# libtool library versioning ... not user-visible (except as part of the
# library file name) and does not correspond to major/minor/micro above
@ -74,31 +79,31 @@ done
# add headers that form the public vips8 API .. don't do a find and exclude,
# we end up excluding almost everything argh
headers="\
basic.h \
vips.h \
object.h \
image.h \
error.h \
foreign.h \
freqfilt.h \
interpolate.h \
header.h \
histogram.h \
operation.h \
enumtypes.h \
conversion.h \
arithmetic.h \
colour.h \
convolution.h \
create.h \
draw.h \
morphology.h \
mosaicing.h \
type.h \
rect.h \
resample.h \
memory.h \
region.h"
basic.h \
vips.h \
object.h \
image.h \
error.h \
foreign.h \
freqfilt.h \
interpolate.h \
header.h \
histogram.h \
operation.h \
enumtypes.h \
conversion.h \
arithmetic.h \
colour.h \
convolution.h \
create.h \
draw.h \
morphology.h \
mosaicing.h \
type.h \
rect.h \
resample.h \
memory.h \
region.h"
for name in $headers; do
vips_introspection_sources="$vips_introspection_sources include/vips/$name"
@ -141,69 +146,35 @@ AM_CONDITIONAL(ENABLE_DEPRECATED, [test x"$enable_deprecated" = x"yes"])
# this gets pasted into version.h as a #define
AC_SUBST(VIPS_ENABLE_DEPRECATED)
AC_MSG_CHECKING([for native Win32])
case "$host" in
*-*-mingw*)
vips_os_win32=yes
;;
*)
vips_os_win32=no
;;
esac
AC_MSG_RESULT([$vips_os_win32])
if test x"$vips_os_win32" = x"yes"; then
AC_DEFINE(OS_WIN32,1,[native win32])
# makes gcc use win native alignment
VIPS_CFLAGS="-mms-bitfields $VIPS_CFLAGS"
fi
# CImg needs flags changed on win32
AM_CONDITIONAL(OS_WIN32, [test x"$vips_os_win32" = x"yes"])
# Cygwin/mingw need binary open to avoid CR/LF madness
# ... should be a better way to test for this
AC_MSG_CHECKING([for binary open needed])
AC_MSG_CHECKING([for -mms-bitfields support])
case "$host_os" in
cygwin* | mingw*)
vips_binary_open=yes
mingw*)
# makes gcc use win native alignment
# GCC >= 4.7 and Clang >= 11 does this automatically, see:
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1510#note_841637
VIPS_CFLAGS="-mms-bitfields $VIPS_CFLAGS"
AC_MSG_RESULT([yes])
;;
*)
vips_binary_open=no
AC_MSG_RESULT([no])
;;
esac
AC_MSG_RESULT([$vips_binary_open])
if test x"$vips_binary_open" = x"yes"; then
AC_DEFINE(BINARY_OPEN,1,[define to open non-text files in binary mode])
fi
AC_MSG_CHECKING([for Mac OS X])
case "$host" in
*-*-darwin*)
vips_os_darwin=yes
;;
*)
vips_os_darwin=no
;;
esac
AC_MSG_RESULT([$vips_os_darwin])
if test x"$vips_os_darwin" = x"yes"; then
AC_DEFINE(VIPS_OS_DARWIN,1,[native Mac OS X])
fi
# set the default directory for ICC profiles
if test x"$vips_os_darwin" = x"yes"; then
profile_dir="/Library/ColorSync/Profiles"
elif test x"$vips_os_win32" = x"yes"; then
# need double escapes since this will get pasted into a #define in a C
# header ... the C:\Windows is usually overrwritten with the result of
# GetWindowsDirectoryW()
profile_dir="C:\\\\Windows\\\\System32\\\\spool\\\\drivers\\\\color"
else
profile_dir="/usr/share/color/icc"
fi
case "$host_os" in
darwin*)
profile_dir="/Library/ColorSync/Profiles"
;;
mingw*)
# need double escapes since this will get pasted into a #define in a C
# header ... the C:\Windows is usually overwritten with the result of
# GetWindowsDirectoryW()
profile_dir="C:\\\\Windows\\\\System32\\\\spool\\\\drivers\\\\color"
;;
*)
profile_dir="/usr/share/color/icc"
;;
esac
AC_DEFINE_UNQUOTED(VIPS_ICC_DIR,"$profile_dir",[default directory for ICC profiles])
# we want largefile support, if possible
@ -219,7 +190,6 @@ AC_PROG_CC_STDC
AC_PROG_CXX
AC_PROG_INSTALL
AC_PROG_LN_S
AM_WITH_DMALLOC
AC_ARG_WITH([doxygen],
AS_HELP_STRING([--without-doxygen], [build without doxygen (default: test)]))
@ -286,7 +256,7 @@ AM_GLIB_GNU_GETTEXT
# [ax_gcc_version_option=yes],
# [ax_gcc_version_option=no]
# )
AC_MSG_CHECKING([for gcc version])
AC_MSG_CHECKING([for $CC version])
GCC_VERSION=""
version=$($CC -dumpversion)
if test $? = 0; then
@ -340,7 +310,7 @@ AC_TYPE_SIZE_T
# g++/gcc 4.x and 5.x have rather broken vector support ... 5.4.1 seems to
# work, but 5.4.0 fails to even compile
AC_MSG_CHECKING([for gcc with working vector support])
AC_MSG_CHECKING([for $CC with working vector support])
if test x"$GCC_VERSION_MAJOR" != x"4" -a x"$GCC_VERSION_MAJOR" != x"5"; then
AC_MSG_RESULT([yes])
else
@ -353,7 +323,7 @@ if test x"$ax_cv_have_var_attribute_vector_size" = x"yes"; then
AC_MSG_CHECKING([for C++ vector shuffle])
AC_LANG_PUSH([C++])
AC_TRY_COMPILE([
typedef float v4f __attribute__((vector_size(4 * sizeof(float))));
typedef float v4f __attribute__((vector_size(4 * sizeof(float)),aligned(16)));
],[
v4f f; f[3] = 99;
],[
@ -376,7 +346,7 @@ if test x"$have_vector_shuffle" = x"yes"; then
AC_MSG_CHECKING([for C++ vector arithmetic])
AC_LANG_PUSH([C++])
AC_TRY_COMPILE([
typedef float v4f __attribute__((vector_size(4 * sizeof(float))));
typedef float v4f __attribute__((vector_size(4 * sizeof(float)),aligned(16)));
],[
v4f f = {1, 2, 3, 4}; f *= 12.0;
v4f g = {5, 6, 7, 8}; f = g > 0 ? g : -1 * g;
@ -396,7 +366,7 @@ if test x"$have_vector_arith" = x"yes"; then
AC_MSG_CHECKING([for C++ signed constants in vector templates])
AC_LANG_PUSH([C++])
AC_TRY_COMPILE([
typedef float v4f __attribute__((vector_size(4 * sizeof(float))));
typedef float v4f __attribute__((vector_size(4 * sizeof(float)),aligned(16)));
template <typename T>
static void
h( v4f B )
@ -423,7 +393,7 @@ fi
AC_FUNC_MEMCMP
AC_FUNC_MMAP
AC_FUNC_VPRINTF
AC_CHECK_FUNCS([getcwd gettimeofday getwd memset munmap putenv realpath strcasecmp strchr strcspn strdup strerror strrchr strspn vsnprintf realpath mkstemp mktemp random rand sysconf atexit])
AC_CHECK_FUNCS([getcwd gettimeofday getwd memset munmap putenv realpath strcasecmp strchr strcspn strdup strerror strrchr strspn vsnprintf realpath mkstemp mktemp random rand sysconf atexit _aligned_malloc posix_memalign memalign])
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.])])
@ -435,20 +405,23 @@ PACKAGES_USED="$PACKAGES_USED glib-2.0 gmodule-2.0 gobject-2.0 gio-2.0"
# 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().]
[define if your glib has g_date_time_format_iso8601().]
)
],
[:
]
)
VIPS_CFLAGS="$VIPS_CFLAGS $GIO_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $GIO_LIBS"
# 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"
LIBS="$LIBS $REQUIRED_LIBS"
CFLAGS="$CFLAGS $REQUIRED_CFLAGS"
AC_CHECK_FUNC(pthread_setattr_default_np,
[AC_DEFINE(HAVE_PTHREAD_DEFAULT_NP,1,[have pthread_setattr_default_np().])
]
@ -456,11 +429,6 @@ AC_CHECK_FUNC(pthread_setattr_default_np,
LIBS="$save_pthread_LIBS"
CFLAGS="$save_pthread_CFLAGS"
if test x"$vips_os_win32" = x"yes"; then
AC_DEFINE(HAVE_G_WIN32_GET_COMMAND_LINE,1,[define if your glib has g_win32_get_command_line().])
have_g_win32_get_command_line=yes
fi
# from 2.48 we have g_uint_checked_mul() etc.
PKG_CHECK_MODULES(HAVE_CHECKED_MUL, glib-2.0 >= 2.48,
[AC_DEFINE(HAVE_CHECKED_MUL,1,[define if your glib has checked multiply.])
@ -486,6 +454,9 @@ if test x"$expat_found" = x"no"; then
exit 1
fi
VIPS_CFLAGS="$VIPS_CFLAGS $EXPAT_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $EXPAT_LIBS"
# optional supporting libraries
AC_ARG_WITH([gsf],
@ -510,13 +481,16 @@ if test x"$with_gsf" != x"no"; then
PKG_CHECK_MODULES(GSF_ZIP64, libgsf-1 >= 1.14.31,
[AC_DEFINE(HAVE_GSF_ZIP64,1,[define if your libgsf supports zip64.])
AC_DEFINE(HAVE_GSF_DEFLATE_LEVEL,1,
[define if your libgsf supports deflate-level.])
[define if your libgsf supports deflate-level.])
],
[:
]
)
fi
VIPS_CFLAGS="$VIPS_CFLAGS $GSF_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $GSF_LIBS"
AC_ARG_WITH([fftw],
AS_HELP_STRING([--without-fftw], [build without fftw (default: test)]))
@ -532,6 +506,9 @@ if test x"$with_fftw" != x"no"; then
)
fi
VIPS_CFLAGS="$VIPS_CFLAGS $FFTW_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $FFTW_LIBS"
# ImageMagick
AC_ARG_WITH([magick],
AS_HELP_STRING([--without-magick], [build without libMagic (default: test)]))
@ -595,7 +572,7 @@ if test x"$magick6" = x"yes"; then
CFLAGS="$CFLAGS $MAGICK_CFLAGS"
AC_CHECK_MEMBER([struct _ImageInfo.number_scenes],
AC_DEFINE(HAVE_NUMBER_SCENES,1,
[define if your magick has ImageInfo.number_scenes.]),
[define if your magick has ImageInfo.number_scenes.]),
[],
[#include <magick/api.h>])
CFLAGS="$save_CFLAGS"
@ -653,11 +630,11 @@ fi
# save but not load, for example
AC_ARG_ENABLE([magickload],
AS_HELP_STRING([--disable-magickload],
[disable libMagic load (default: enabled)]))
[disable libMagic load (default: enabled)]))
AC_ARG_ENABLE([magicksave],
AS_HELP_STRING([--disable-magicksave],
[disable libMagic save (default: enabled)]))
[disable libMagic save (default: enabled)]))
if test x"$enable_magicksave" != x"yes"; then
# we need ImportImagePixels ... GM is missing this sadly
@ -665,12 +642,12 @@ if test x"$enable_magicksave" != x"yes"; then
LIBS="$LIBS $MAGICK_LIBS"
AC_CHECK_FUNCS(ImportImagePixels,[
AC_DEFINE(HAVE_IMPORTIMAGEPIXELS,1,
[define if you have ImportImagePixels.])
[define if you have ImportImagePixels.])
],[]
)
AC_CHECK_FUNCS(ImagesToBlob,[
AC_DEFINE(HAVE_IMAGESTOBLOB,1,
[define if you have ImagesToBlob.])
[define if you have ImagesToBlob.])
],[]
)
LIBS="$save_LIBS"
@ -691,6 +668,9 @@ else
enable_magicksave=no
fi
VIPS_CFLAGS="$VIPS_CFLAGS $MAGICK_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $MAGICK_LIBS"
# orc
AC_ARG_WITH([orc],
AS_HELP_STRING([--without-orc], [build without orc (default: test)]))
@ -705,7 +685,7 @@ if test x"$with_orc" != x"no"; then
LIBS="$LIBS $ORC_LIBS"
AC_CHECK_FUNCS(orc_program_get_error,
AC_DEFINE(HAVE_ORC_PROGRAM_GET_ERROR,1,
[define if your orc has orc_program_get_error.]))
[define if your orc has orc_program_get_error.]))
LIBS="$save_LIBS"
],
[AC_MSG_WARN([orc-0.4.11 or later not found; disabling orc support])
@ -719,7 +699,7 @@ fi
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.]
[define if your orc works with cf-protection.]
)
],
[:
@ -727,6 +707,9 @@ if test x"$with_orc" = x"yes"; then
)
fi
VIPS_CFLAGS="$VIPS_CFLAGS $ORC_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $ORC_LIBS"
# lcms ... refuse to use lcms1
AC_ARG_WITH([lcms],
AS_HELP_STRING([--without-lcms], [build without lcms (default: test)]))
@ -747,6 +730,9 @@ fi
# is detected
AM_CONDITIONAL(ENABLE_LCMS, [test x"$with_lcms" != x"no"])
VIPS_CFLAGS="$VIPS_CFLAGS $LCMS_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $LCMS_LIBS"
# OpenEXR
AC_ARG_WITH([OpenEXR],
AS_HELP_STRING([--without-OpenEXR], [build without OpenEXR (default: test)]))
@ -764,6 +750,9 @@ if test x"$with_OpenEXR" != x"no"; then
)
fi
VIPS_CFLAGS="$VIPS_CFLAGS $OPENEXR_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $OPENEXR_LIBS"
# nifti
AC_ARG_WITH([nifti],
AS_HELP_STRING([--without-nifti], [build without nifti (default: test)]))
@ -777,6 +766,40 @@ if test x"$with_nifti" != x"no"; then
)
fi
VIPS_CFLAGS="$VIPS_CFLAGS $NIFTI_CFLAGS"
VIPS_INCLUDES="$VIPS_INCLUDES $NIFTI_INCLUDES"
VIPS_LIBS="$VIPS_LIBS $NIFTI_LIBS"
# openjpeg
AC_ARG_WITH([libopenjp2],
AS_HELP_STRING([--without-libopenjp2],
[build without libopenjp2 (default: test)]))
if test x"$with_libopenjp2" != x"no"; then
PKG_CHECK_MODULES(LIBOPENJP2, libopenjp2 >= 2.3,
[AC_DEFINE(HAVE_LIBOPENJP2,1,
[define if you have libopenjp2 >=2.2 installed.])
with_libopenjp2=yes
PACKAGES_USED="$PACKAGES_USED libopenjp2"
],
[AC_MSG_WARN([libopenjp2 not found; disabling libopenjp2 support])
with_libopenjp2=no
]
)
# 2.3 and earlier have threading problems
PKG_CHECK_MODULES(LIBOPENJP2_THREADING, libopenjp2 >= 2.4,
[AC_DEFINE(HAVE_LIBOPENJP2_THREADING,1,[define if your libopenjp2 threading works.])
],
[:
]
)
fi
VIPS_CFLAGS="$VIPS_CFLAGS $LIBOPENJP2_CFLAGS"
VIPS_INCLUDES="$VIPS_INCLUDES $LIBOPENJP2_INCLUDES"
VIPS_LIBS="$VIPS_LIBS $LIBOPENJP2_LIBS"
# libheif
AC_ARG_WITH([heif],
AS_HELP_STRING([--without-heif], [build without libheif (default: test)]))
@ -790,13 +813,13 @@ if test x"$with_heif" != x"no"; then
# this variable
if test x"$have_h265_decoder" != x"no" -o x"$have_avif_decoder" = x"yes"; then
AC_DEFINE(HAVE_HEIF_DECODER,1,
[define if your libheif has decode support.])
[define if your libheif has decode support.])
fi
have_h265_encoder=`$PKG_CONFIG libheif --variable builtin_h265_encoder`
have_avif_encoder=`$PKG_CONFIG libheif --variable builtin_avif_encoder`
if test x"$have_h265_encoder" != x"no" -o x"$have_avif_encoder" = x"yes"; then
AC_DEFINE(HAVE_HEIF_ENCODER,1,
[define if your libheif has encode support.])
[define if your libheif has encode support.])
fi
PACKAGES_USED="$PACKAGES_USED libheif"
],
@ -817,7 +840,7 @@ if test x"$with_heif" = x"yes"; then
LIBS="$LIBS $HEIF_LIBS"
AC_CHECK_FUNCS(heif_image_handle_get_raw_color_profile,[
AC_DEFINE(HAVE_HEIF_COLOR_PROFILE,1,
[define if you have heif_image_handle_get_raw_color_profile.])
[define if you have heif_image_handle_get_raw_color_profile.])
],[]
)
LIBS="$save_LIBS"
@ -838,12 +861,15 @@ if test x"$with_heif" = x"yes"; then
CFLAGS="$CFLAGS $HEIF_CFLAGS"
AC_CHECK_MEMBER([struct heif_decoding_options.convert_hdr_to_8bit],[
AC_DEFINE(HAVE_HEIF_DECODING_OPTIONS_CONVERT_HDR_TO_8BIT,1,
[define if you have heif_decoding_options.convert_hdr_to_8bit])
[define if you have heif_decoding_options.convert_hdr_to_8bit])
],[],
[#include <libheif/heif.h>])
CFLAGS="$save_CFLAGS"
fi
VIPS_CFLAGS="$VIPS_CFLAGS $HEIF_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $HEIF_LIBS"
# pdfium
AC_ARG_WITH([pdfium],
AS_HELP_STRING([--without-pdfium], [build without pdfium (default: test)]))
@ -864,6 +890,9 @@ if test x"$with_pdfium" != x"no"; then
])
fi
VIPS_CFLAGS="$VIPS_CFLAGS $PDFIUM_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $PDFIUM_LIBS"
# poppler
AC_ARG_WITH([poppler],
AS_HELP_STRING([--without-poppler], [build without poppler (default: test)]))
@ -879,6 +908,9 @@ if test x"$with_poppler" != x"no"; then
])
fi
VIPS_CFLAGS="$VIPS_CFLAGS $POPPLER_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $POPPLER_LIBS"
# librsvg
AC_ARG_WITH([rsvg],
AS_HELP_STRING([--without-rsvg], [build without rsvg (default: test)]))
@ -895,6 +927,9 @@ if test x"$with_rsvg" != x"no"; then
])
fi
VIPS_CFLAGS="$VIPS_CFLAGS $RSVG_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $RSVG_LIBS"
# zlib
# some platforms, like macosx, are missing the .pc files for zlib, so
# we fall back to FIND_ZLIB
@ -918,6 +953,10 @@ if test x"$with_zlib" != x"no"; then
)
fi
VIPS_CFLAGS="$VIPS_CFLAGS $ZLIB_CFLAGS"
VIPS_INCLUDES="$VIPS_INCLUDES $ZLIB_INCLUDES"
VIPS_LIBS="$VIPS_LIBS $ZLIB_LIBS"
# OpenSlide
AC_ARG_WITH([openslide],
AS_HELP_STRING([--without-openslide],
@ -945,6 +984,9 @@ if test x"$with_openslide" != x"no"; then
)
fi
VIPS_CFLAGS="$VIPS_CFLAGS $OPENSLIDE_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $OPENSLIDE_LIBS"
# matio
AC_ARG_WITH([matio],
AS_HELP_STRING([--without-matio], [build without matio (default: test)]))
@ -961,9 +1003,22 @@ if test x"$with_matio" != x"no"; then
)
fi
VIPS_CFLAGS="$VIPS_CFLAGS $MATIO_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $MATIO_LIBS"
# not external libraries, but have options to disable them, helps to
# reduce attack surface
AC_ARG_WITH([nsgif],
AS_HELP_STRING([--without-nsgif], [build without nsgif load (default: with)]))
if test x"$with_nsgif" != x"no"; then
AC_DEFINE(HAVE_NSGIF,1,[define to build nsgif load support.])
with_nsgif=yes
fi
AM_CONDITIONAL(ENABLE_NSGIF, [test x"$with_nsgif" = x"yes"])
AC_ARG_WITH([ppm],
AS_HELP_STRING([--without-ppm], [build without ppm (default: with)]))
@ -1004,6 +1059,9 @@ if test x"$with_cfitsio" != x"no"; then
)
fi
VIPS_CFLAGS="$VIPS_CFLAGS $CFITSIO_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $CFITSIO_LIBS"
# libwebp ... target 0.6+ to reduce complication
# webp has the stuff for handling metadata in two separate libraries -- we
# insit on having all of them
@ -1022,23 +1080,49 @@ if test x"$with_libwebp" != x"no"; then
)
fi
# pangoft2
AC_ARG_WITH([pangoft2],
AS_HELP_STRING([--without-pangoft2],
[build without pangoft2 (default: test)]))
VIPS_CFLAGS="$VIPS_CFLAGS $LIBWEBP_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $LIBWEBP_LIBS"
if test x"$with_pangoft2" != x"no"; then
PKG_CHECK_MODULES(PANGOFT2, pangoft2,
[AC_DEFINE(HAVE_PANGOFT2,1,[define if you have pangoft2 installed.])
with_pangoft2=yes
PACKAGES_USED="$PACKAGES_USED pangoft2"
# pangocairo for text rendering
AC_ARG_WITH([pangocairo],
AS_HELP_STRING([--without-pangocairo],
[build without pangocairo (default: test)]))
if test x"$with_pangocairo" != x"no"; then
PKG_CHECK_MODULES(PANGOCAIRO, pangocairo,
[AC_DEFINE(HAVE_PANGOCAIRO,1,[define if you have pangocairo installed.])
with_pangocairo=yes
PACKAGES_USED="$PACKAGES_USED pangocairo"
],
[AC_MSG_WARN([pangoft2 not found; disabling pangoft2 support])
with_pangoft2=no
[AC_MSG_WARN([pangocairo not found; disabling pangocairo support])
with_pangocairo=no
]
)
fi
VIPS_CFLAGS="$VIPS_CFLAGS $PANGOCAIRO_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $PANGOCAIRO_LIBS"
# font file support with fontconfig
AC_ARG_WITH([fontconfig],
AS_HELP_STRING([--without-fontconfig],
[build without fontconfig (default: test)]))
if test x"$with_pangocairo" != x"no" -a x"$with_fontconfig" != x"no"; then
PKG_CHECK_MODULES(FONTCONFIG, fontconfig,
[AC_DEFINE(HAVE_FONTCONFIG,1,[define if you have fontconfig installed.])
with_fontconfig=yes
PACKAGES_USED="$PACKAGES_USED fontconfig"
],
[AC_MSG_WARN([fontconfig not found; disabling fontconfig support])
with_fontconfig=no
]
)
fi
VIPS_CFLAGS="$VIPS_CFLAGS $FONTCONFIG_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $FONTCONFIG_LIBS"
# look for TIFF with pkg-config ... fall back to our tester
# pkgconfig support for libtiff starts with libtiff-4
AC_ARG_WITH([tiff],
@ -1074,14 +1158,9 @@ if test x"$with_tiff" != x"no"; then
INCLUDES="$save_INCLUDES"
fi
# giflib
FIND_GIFLIB(
[with_giflib="yes (found by search)"
],
[AC_MSG_WARN([giflib not found; disabling direct GIF support])
with_giflib=no
]
)
VIPS_CFLAGS="$VIPS_CFLAGS $TIFF_CFLAGS"
VIPS_INCLUDES="$VIPS_INCLUDES $TIFF_INCLUDES"
VIPS_LIBS="$VIPS_LIBS $TIFF_LIBS"
# Look for libspng first
# 0.6.1 uses "libspng.pc", git master libspng uses "spng.pc"
@ -1106,6 +1185,9 @@ if test x"$with_libspng" != x"no"; then
)
fi
VIPS_CFLAGS="$VIPS_CFLAGS $SPNG_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $SPNG_LIBS"
# look for PNG with pkg-config ... fall back to our tester
# we can have both PNG and SPNG enabled, with SPNG for read and PNG for
# write
@ -1136,11 +1218,15 @@ if test x"$with_png" != x"no"; then
CFLAGS="$PNG_INCLUDES $CFLAGS"
AC_CHECK_FUNCS(png_set_chunk_malloc_max,
AC_DEFINE(HAVE_PNG_SET_CHUNK_MALLOC_MAX,1,
[define if your libpng has png_set_chunk_malloc_max.]))
[define if your libpng has png_set_chunk_malloc_max.]))
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
fi
VIPS_CFLAGS="$VIPS_CFLAGS $PNG_CFLAGS"
VIPS_INCLUDES="$VIPS_INCLUDES $PNG_INCLUDES"
VIPS_LIBS="$VIPS_LIBS $PNG_LIBS"
# look for libimagequant with pkg-config (only if libpng is enabled)
AC_ARG_WITH([imagequant],
AS_HELP_STRING([--without-imagequant], [build without imagequant (default: test)]))
@ -1159,6 +1245,9 @@ else
with_imagequant=no
fi
VIPS_CFLAGS="$VIPS_CFLAGS $IMAGEQUANT_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $IMAGEQUANT_LIBS"
# look for libjpeg with pkg-config ... fall back to our tester
AC_ARG_WITH([jpeg],
AS_HELP_STRING([--without-jpeg], [build without libjpeg (default: test)]))
@ -1191,11 +1280,15 @@ if test x"$with_jpeg" != x"no"; then
CFLAGS="$JPEG_INCLUDES $CFLAGS"
AC_CHECK_FUNCS(jpeg_c_bool_param_supported,
AC_DEFINE(HAVE_JPEG_EXT_PARAMS,1,
[define if your libjpeg has extension parameters.]))
[define if your libjpeg has extension parameters.]))
LIBS="$save_LIBS"
CFLAGS="$save_CFLAGS"
fi
VIPS_CFLAGS="$VIPS_CFLAGS $JPEG_CFLAGS"
VIPS_INCLUDES="$VIPS_INCLUDES $JPEG_INCLUDES"
VIPS_LIBS="$VIPS_LIBS $JPEG_LIBS"
# libexif
AC_ARG_WITH([libexif],
AS_HELP_STRING([--without-libexif], [build without libexif (default: test)]))
@ -1223,6 +1316,9 @@ if test x"$with_libexif" != x"no"; then
CPPFLAGS="$save_CPPFLAGS"
fi
VIPS_CFLAGS="$VIPS_CFLAGS $EXIF_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $EXIF_LIBS"
# fuzzing
AC_ARG_VAR([LIB_FUZZING_ENGINE],
[fuzzing library, e.g. /path/to/libFuzzer.a])
@ -1230,14 +1326,48 @@ if test x"$LIB_FUZZING_ENGINE" = x; then
LIB_FUZZING_ENGINE="libstandaloneengine.a"
fi
# Gather all up for VIPS_CFLAGS, VIPS_INCLUDES, VIPS_LIBS
VIPS_CFLAGS="$VIPS_CFLAGS $GTHREAD_CFLAGS $GIO_CFLAGS $REQUIRED_CFLAGS $EXPAT_CFLAGS $ZLIB_CFLAGS $PANGOFT2_CFLAGS $GSF_CFLAGS $FFTW_CFLAGS $MAGICK_CFLAGS $JPEG_CFLAGS $SPNG_CFLAGS $PNG_CFLAGS $IMAGEQUANT_CFLAGS $EXIF_CFLAGS $MATIO_CFLAGS $CFITSIO_CFLAGS $LIBWEBP_CFLAGS $LIBWEBPMUX_CFLAGS $GIFLIB_INCLUDES $RSVG_CFLAGS $PDFIUM_CFLAGS $POPPLER_CFLAGS $OPENEXR_CFLAGS $OPENSLIDE_CFLAGS $ORC_CFLAGS $TIFF_CFLAGS $LCMS_CFLAGS $HEIF_CFLAGS" VIPS_CFLAGS="$VIPS_DEBUG_FLAGS $VIPS_CFLAGS"
VIPS_INCLUDES="$ZLIB_INCLUDES $PNG_INCLUDES $TIFF_INCLUDES $JPEG_INCLUDES $NIFTI_INCLUDES"
VIPS_LIBS="$ZLIB_LIBS $HEIF_LIBS $MAGICK_LIBS $SPNG_LIBS $PNG_LIBS $IMAGEQUANT_LIBS $TIFF_LIBS $JPEG_LIBS $GTHREAD_LIBS $GIO_LIBS $REQUIRED_LIBS $EXPAT_LIBS $PANGOFT2_LIBS $GSF_LIBS $FFTW_LIBS $ORC_LIBS $LCMS_LIBS $GIFLIB_LIBS $RSVG_LIBS $NIFTI_LIBS $PDFIUM_LIBS $POPPLER_LIBS $OPENEXR_LIBS $OPENSLIDE_LIBS $CFITSIO_LIBS $LIBWEBP_LIBS $LIBWEBPMUX_LIBS $MATIO_LIBS $EXIF_LIBS -lm"
VIPS_CFLAGS="$VIPS_CFLAGS $VIPS_DEBUG_FLAGS $REQUIRED_CFLAGS"
VIPS_LIBS="$VIPS_LIBS $REQUIRED_LIBS -lm"
# autoconf hates multi-line AC_SUBST so we have to have another copy of this
# thing
VIPS_CONFIG="native win32: $vips_os_win32, native OS X: $vips_os_darwin, open files in binary mode: $vips_binary_open, enable debug: $enable_debug, enable deprecated library components: $enable_deprecated, enable docs with gtkdoc: $enable_gtk_doc, gobject introspection: $found_introspection, enable radiance support: $with_radiance, enable analyze support: $with_analyze, enable PPM support: $with_ppm, generate C++ docs: $with_doxygen, use fftw3 for FFT: $with_fftw, Magick package: $with_magickpackage, Magick API version: $magick_version, load with libMagick: $enable_magickload, save with libMagick: $enable_magicksave, accelerate loops with orc: $with_orc, ICC profile support with lcms: $with_lcms, file import with niftiio: $with_nifti, file import with libheif: $with_heif, file import with OpenEXR: $with_OpenEXR, file import with OpenSlide: $with_openslide, file import with matio: $with_matio, PDF import with PDFium: $with_pdfium, PDF import with poppler-glib: $with_poppler, SVG import with librsvg-2.0: $with_rsvg, zlib: $with_zlib, file import with cfitsio: $with_cfitsio, file import/export with libwebp: $with_libwebp, text rendering with pangoft2: $with_pangoft2, file import/export with libspng: $with_libspng, file import/export with libpng: $with_png, support 8bpp PNG quantisation: $with_imagequant, file import/export with libtiff: $with_tiff, file import/export with giflib: $with_giflib, file import/export with libjpeg: $with_jpeg, image pyramid export: $with_gsf, use libexif to load/save JPEG metadata: $with_libexif"
VIPS_CONFIG="\
enable debug: $enable_debug, \
enable deprecated library components: $enable_deprecated, \
enable docs with gtkdoc: $enable_gtk_doc, \
gobject introspection: $found_introspection, \
RAD load/save: $with_radiance, \
Analyze7 load/save: $with_analyze, \
PPM load/save: $with_ppm, \
GIF load: $with_nsgif, \
generate C++ docs: $with_doxygen, \
use fftw3 for FFT: $with_fftw, \
accelerate loops with orc: $with_orc, \
ICC profile support with lcms: $with_lcms, \
zlib: $with_zlib, \
text rendering with pangocairo: $with_pangocairo, \
font file support with fontconfig: $with_fontconfig, \
EXIF metadata support with libexif: $with_libexif, \
JPEG load/save with libjpeg: $with_jpeg, \
PNG load with libspng: $with_libspng, \
PNG load/save with libpng: $with_png, \
8bpp PNG quantisation: $with_imagequant, \
TIFF load/save with libtiff: $with_tiff, \
image pyramid save: $with_gsf, \
HEIC/AVIF load/save with libheif: $with_heif, \
WebP load/save with libwebp: $with_libwebp, \
PDF load with PDFium: $with_pdfium, \
PDF load with poppler-glib: $with_poppler, \
SVG load with librsvg-2.0: $with_rsvg, \
EXR load with OpenEXR: $with_OpenEXR, \
slide load with OpenSlide: $with_openslide, \
Matlab load with matio: $with_matio, \
NIfTI load/save with niftiio: $with_nifti, \
FITS load/save with cfitsio: $with_cfitsio, \
Magick package: $with_magickpackage, \
Magick API version: $magick_version, \
load with libMagickCore: $enable_magickload, \
save with libMagickCore: $enable_magicksave"
AC_SUBST(VIPS_LIBDIR)
@ -1254,108 +1384,103 @@ TOP_SRCDIR=$ac_pwd
AC_SUBST(TOP_SRCDIR)
AC_CONFIG_FILES([
vips.pc
vips-cpp.pc
Makefile
$srcdir/libvips/include/vips/version.h
libvips/include/Makefile
libvips/include/vips/Makefile
libvips/Makefile
libvips/arithmetic/Makefile
libvips/colour/Makefile
libvips/colour/profiles/Makefile
libvips/conversion/Makefile
libvips/convolution/Makefile
libvips/deprecated/Makefile
libvips/foreign/Makefile
libvips/freqfilt/Makefile
libvips/histogram/Makefile
libvips/draw/Makefile
libvips/iofuncs/Makefile
libvips/morphology/Makefile
libvips/mosaicing/Makefile
libvips/create/Makefile
libvips/resample/Makefile
cplusplus/Doxyfile
cplusplus/include/Makefile
cplusplus/include/vips/Makefile
cplusplus/Makefile
tools/Makefile
tools/batch_crop
tools/batch_image_convert
tools/batch_rubber_sheet
tools/light_correct
tools/shrink_width
test/Makefile
test/variables.sh
test/test-suite/Makefile
test/test-suite/helpers/Makefile
man/Makefile
doc/Makefile
doc/libvips-docs.xml
po/Makefile.in
fuzz/Makefile
vips.pc
vips-cpp.pc
Makefile
$srcdir/libvips/include/vips/version.h
libvips/include/Makefile
libvips/include/vips/Makefile
libvips/Makefile
libvips/arithmetic/Makefile
libvips/colour/Makefile
libvips/colour/profiles/Makefile
libvips/conversion/Makefile
libvips/convolution/Makefile
libvips/deprecated/Makefile
libvips/foreign/Makefile
libvips/foreign/libnsgif/Makefile
libvips/freqfilt/Makefile
libvips/histogram/Makefile
libvips/draw/Makefile
libvips/iofuncs/Makefile
libvips/morphology/Makefile
libvips/mosaicing/Makefile
libvips/create/Makefile
libvips/resample/Makefile
cplusplus/Doxyfile
cplusplus/include/Makefile
cplusplus/include/vips/Makefile
cplusplus/Makefile
tools/Makefile
tools/batch_crop
tools/batch_image_convert
tools/batch_rubber_sheet
tools/light_correct
tools/shrink_width
test/Makefile
test/variables.sh
test/test-suite/Makefile
test/test-suite/helpers/Makefile
man/Makefile
doc/Makefile
doc/libvips-docs.xml
po/Makefile.in
fuzz/Makefile
])
AC_OUTPUT
# also add any new items to VIPS_CONFIG above
AC_MSG_RESULT([dnl
* build options
native win32: $vips_os_win32
native OS X: $vips_os_darwin
open files in binary mode: $vips_binary_open
enable debug: $enable_debug
enable deprecated library components: $enable_deprecated
enable docs with gtkdoc: $enable_gtk_doc
gobject introspection: $found_introspection
enable radiance support: $with_radiance
enable analyze support: $with_analyze
enable PPM support: $with_ppm
## Build options
enable debug: $enable_debug
enable deprecated library components: $enable_deprecated
enable docs with gtkdoc: $enable_gtk_doc
gobject introspection: $found_introspection
RAD load/save: $with_radiance
Analyze7 load/save: $with_analyze
PPM load/save: $with_ppm
GIF load: $with_nsgif
generate C++ docs: $with_doxygen
* optional dependencies
use fftw3 for FFT: $with_fftw
Magick package: $with_magickpackage
Magick API version: $magick_version
load with libMagick: $enable_magickload
save with libMagick: $enable_magicksave
accelerate loops with orc: $with_orc
(requires orc-0.4.11 or later)
ICC profile support with lcms: $with_lcms
file import with niftiio: $with_nifti
file import with libheif: $with_heif
file import with OpenEXR: $with_OpenEXR
file import with OpenSlide: $with_openslide
(requires openslide-3.3.0 or later)
file import with matio: $with_matio
PDF import with PDFium: $with_pdfium
PDF import with poppler-glib: $with_poppler
(requires poppler-glib 0.16.0 or later)
SVG import with librsvg-2.0: $with_rsvg
(requires librsvg-2.0 2.34.0 or later)
zlib: $with_zlib
file import with cfitsio: $with_cfitsio
file import/export with libwebp: $with_libwebp
(requires libwebp, libwebpmux, libwebpdemux 0.6.0 or later)
text rendering with pangoft2: $with_pangoft2
file import/export with libspng: $with_libspng
(requires libspng-0.6 or later)
file import/export with libpng: $with_png
(requires libpng-1.2.9 or later)
support 8bpp PNG quantisation: $with_imagequant
(requires libimagequant)
file import/export with libtiff: $with_tiff
file import/export with giflib: $with_giflib
file import/export with libjpeg: $with_jpeg
image pyramid export: $with_gsf
(requires libgsf-1 1.14.26 or later)
use libexif to load/save JPEG metadata: $with_libexif
])
## Optional dependencies
use fftw3 for FFT: $with_fftw
accelerate loops with orc: $with_orc
(requires orc-0.4.11 or later)
ICC profile support with lcms: $with_lcms
zlib: $with_zlib
text rendering with pangocairo: $with_pangocairo
font file support with fontconfig: $with_fontconfig
EXIF metadata support with libexif: $with_libexif
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
Your glib is too old, vips will not support unicode command-line arguments.
])
fi
fi
## File format support
JPEG load/save with libjpeg: $with_jpeg
PNG load with libspng: $with_libspng
(requires libspng-0.6 or later)
PNG load/save with libpng: $with_png
(requires libpng-1.2.9 or later)
8bpp PNG quantisation: $with_imagequant
(requires libimagequant)
TIFF load/save with libtiff: $with_tiff
image pyramid save: $with_gsf
(requires libgsf-1 1.14.26 or later)
HEIC/AVIF load/save with libheif: $with_heif
WebP load/save with libwebp: $with_libwebp
(requires libwebp, libwebpmux, libwebpdemux 0.6.0 or later)
PDF load with PDFium: $with_pdfium
PDF load with poppler-glib: $with_poppler
(requires poppler-glib 0.16.0 or later)
SVG load with librsvg-2.0: $with_rsvg
(requires librsvg-2.0 2.34.0 or later)
EXR load with OpenEXR: $with_OpenEXR
JPEG2000 load/save with libopenjp2: $with_libopenjp2
(requires libopenjp2 2.2 or later)
slide load with OpenSlide: $with_openslide
(requires openslide-3.3.0 or later)
Matlab load with matio: $with_matio
NIfTI load/save with niftiio: $with_nifti
FITS load/save with cfitsio: $with_cfitsio
Magick package: $with_magickpackage
Magick API version: $magick_version
load with libMagickCore: $enable_magickload
save with libMagickCore: $enable_magicksave
])

View File

@ -263,12 +263,6 @@ TAB_SIZE = 8
ALIASES =
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding "class=itcl::class"
# will allow you to use the command class in the itcl::class meaning.
TCL_SUBST =
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C. For
# instance, some of the names that are used will be different. The list of all

View File

@ -42,6 +42,9 @@ install-htmlDATA:
-mkdir -p $(DESTDIR)$(htmldir)
-cp -r html $(DESTDIR)$(htmldir)
uninstall-htmlDATA:
rm -rf $(DESTDIR)$(htmldir)/html
EXTRA_DIST = \
README.md \
vips-operators.cpp \

View File

@ -5,9 +5,10 @@ pkginclude_HEADERS = \
VConnection8.h \
vips8
vips-operators.h:
echo "// headers for vips operations" > vips-operators.h; \
echo -n "// " >> vips-operators.h; \
date >> vips-operators.h; \
echo "// this file is generated automatically, do not edit!" >> vips-operators.h; \
./../../gen-operators.py -g h >> vips-operators.h
vips-operators:
echo "// headers for vips operations" > vips-operators; \
echo "// paste this file into VImage8.h, do not leave in repo" > vips-operators; \
echo -n "// " >> vips-operators; \
date >> vips-operators; \
echo "// this file is generated automatically, do not edit!" >> vips-operators; \
./../../gen-operators.py -g h >> vips-operators

View File

@ -600,6 +600,29 @@ public:
static_cast<int>( value.size() ) );
}
/**
* Set the value of an double array metadata item on an image.
*
* A copy of the array is taken.
*/
void
set( const char *field, double *value, int n )
{
vips_image_set_array_double( this->get_image(), field, value, n );
}
/**
* Set the value of an double array metadata item on an image.
*
* A copy of the array is taken.
*/
void
set( const char *field, std::vector<double> value )
{
vips_image_set_array_double( this->get_image(), field, &value[0],
static_cast<int>( value.size() ) );
}
/**
* Set the value of a double metadata item on an image.
*/
@ -695,6 +718,40 @@ public:
return( vector );
}
/**
* Get the value of a metadata item as an array of doubles. Do not free
* the result.
*
* If the item is not of this type, an exception is thrown.
*/
void
get_array_double( const char *field, double **out, int *n ) const
{
if( vips_image_get_array_double( this->get_image(),
field, out, n ) )
throw( VError() );
}
/**
* Get the value of a metadata item as an array of doubles.
*
* If the item is not of this type, an exception is thrown.
*/
std::vector<double>
get_array_double( const char *field ) const
{
int length;
double *array;
if( vips_image_get_array_double( this->get_image(),
field, &array, &length ) )
throw( VError() );
std::vector<double> vector( array, array + length );
return( vector );
}
/**
* Get the value of a metadata item as a double.
*
@ -1724,7 +1781,7 @@ public:
*
* Rebuild with:
*
* make vips-operators.h
* make vips-operators
*
* Then delete from here to the end of the class and paste in
* vips-operators.h. We could just #include vips-operators.h, but
@ -1732,7 +1789,7 @@ public:
*/
// headers for vips operations
// Wed 19 Aug 14:34:56 BST 2020
// Wed Apr 21 06:00:31 PM CEST 2021
// this file is generated automatically, do not edit!
/**
@ -2679,6 +2736,22 @@ int find_trim( int *top, int *width, int *height, VOption *options = 0 ) const;
*/
static VImage fitsload( const char *filename, VOption *options = 0 );
/**
* Load fits from a source.
*
* **Optional parameters**
* - **memory** -- Force open via memory, bool.
* - **access** -- Required access pattern for this file, VipsAccess.
* - **sequential** -- Sequential read only, bool.
* - **fail** -- Fail on first error, bool.
* - **disc** -- Open to disc, bool.
*
* @param source Source to load from.
* @param options Set of options.
* @return Output image.
*/
static VImage fitsload_source( VSource source, VOption *options = 0 );
/**
* Save image to fits file.
*
@ -2789,6 +2862,7 @@ static VImage gaussmat( double sigma, double min_ampl, VOption *options = 0 );
* **Optional parameters**
* - **sigma** -- Standard deviation of pixels in generated image, double.
* - **mean** -- Mean of pixels in generated image, double.
* - **seed** -- Random number seed, int.
*
* @param width Image width in pixels.
* @param height Image height in pixels.
@ -2807,11 +2881,11 @@ static VImage gaussnoise( int width, int height, VOption *options = 0 );
std::vector<double> getpoint( int x, int y, VOption *options = 0 ) const;
/**
* Load gif with giflib.
* Load gif with libnsgif.
*
* **Optional parameters**
* - **page** -- Load this page from the file, int.
* - **n** -- Load this many pages, int.
* - **page** -- Load this page from the file, int.
* - **memory** -- Force open via memory, bool.
* - **access** -- Required access pattern for this file, VipsAccess.
* - **sequential** -- Sequential read only, bool.
@ -2825,11 +2899,11 @@ std::vector<double> getpoint( int x, int y, VOption *options = 0 ) const;
static VImage gifload( const char *filename, VOption *options = 0 );
/**
* Load gif with giflib.
* Load gif with libnsgif.
*
* **Optional parameters**
* - **page** -- Load this page from the file, int.
* - **n** -- Load this many pages, int.
* - **page** -- Load this page from the file, int.
* - **memory** -- Force open via memory, bool.
* - **access** -- Required access pattern for this file, VipsAccess.
* - **sequential** -- Sequential read only, bool.
@ -2843,11 +2917,11 @@ static VImage gifload( const char *filename, VOption *options = 0 );
static VImage gifload_buffer( VipsBlob *buffer, VOption *options = 0 );
/**
* Load gif with giflib.
* Load gif from source.
*
* **Optional parameters**
* - **page** -- Load this page from the file, int.
* - **n** -- Load this many pages, int.
* - **page** -- Load this page from the file, int.
* - **memory** -- Force open via memory, bool.
* - **access** -- Required access pattern for this file, VipsAccess.
* - **sequential** -- Sequential read only, bool.
@ -2977,13 +3051,13 @@ static VImage heifload_source( VSource source, VOption *options = 0 );
* - **Q** -- Q factor, int.
* - **lossless** -- Enable lossless compression, bool.
* - **compression** -- Compression format, VipsForeignHeifCompression.
* - **speed**: -- CPU effort, 0 slowest - 8 fastest, AV1 compression only, int.
* - **speed** -- CPU effort, int.
* - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample.
* - **strip** -- Strip all metadata from image, bool.
* - **background** -- Background value, std::vector<double>.
* - **page_height** -- Set page height for multipage save, int.
*
* @param filename Filename to load from.
* @param filename Filename to save to.
* @param options Set of options.
*/
void heifsave( const char *filename, VOption *options = 0 ) const;
@ -2995,7 +3069,7 @@ void heifsave( const char *filename, VOption *options = 0 ) const;
* - **Q** -- Q factor, int.
* - **lossless** -- Enable lossless compression, bool.
* - **compression** -- Compression format, VipsForeignHeifCompression.
* - **speed**: -- CPU effort, 0 slowest - 8 fastest, AV1 compression only, int.
* - **speed** -- CPU effort, int.
* - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample.
* - **strip** -- Strip all metadata from image, bool.
* - **background** -- Background value, std::vector<double>.
@ -3013,7 +3087,7 @@ VipsBlob *heifsave_buffer( VOption *options = 0 ) const;
* - **Q** -- Q factor, int.
* - **lossless** -- Enable lossless compression, bool.
* - **compression** -- Compression format, VipsForeignHeifCompression.
* - **speed**: -- CPU effort, 0 slowest - 8 fastest, AV1 compression only, int.
* - **speed** -- CPU effort, int.
* - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample.
* - **strip** -- Strip all metadata from image, bool.
* - **background** -- Background value, std::vector<double>.
@ -3156,6 +3230,7 @@ VImage hough_line( VOption *options = 0 ) const;
* **Optional parameters**
* - **pcs** -- Set Profile Connection Space, VipsPCS.
* - **intent** -- Rendering intent, VipsIntent.
* - **black_point_compensation** -- Enable black point compensation, bool.
* - **output_profile** -- Filename to load output profile from, const char *.
* - **depth** -- Output device space depth in bits, int.
*
@ -3170,6 +3245,7 @@ VImage icc_export( VOption *options = 0 ) const;
* **Optional parameters**
* - **pcs** -- Set Profile Connection Space, VipsPCS.
* - **intent** -- Rendering intent, VipsIntent.
* - **black_point_compensation** -- Enable black point compensation, bool.
* - **embedded** -- Use embedded input profile, if available, bool.
* - **input_profile** -- Filename to load input profile from, const char *.
*
@ -3184,6 +3260,7 @@ VImage icc_import( VOption *options = 0 ) const;
* **Optional parameters**
* - **pcs** -- Set Profile Connection Space, VipsPCS.
* - **intent** -- Rendering intent, VipsIntent.
* - **black_point_compensation** -- Enable black point compensation, bool.
* - **embedded** -- Use embedded input profile, if available, bool.
* - **input_profile** -- Filename to load input profile from, const char *.
* - **depth** -- Output device space depth in bits, int.
@ -3280,6 +3357,111 @@ VImage invfft( VOption *options = 0 ) const;
*/
VImage join( VImage in2, VipsDirection direction, VOption *options = 0 ) const;
/**
* Load jpeg2000 image.
*
* **Optional parameters**
* - **page** -- Load this page from the image, int.
* - **memory** -- Force open via memory, bool.
* - **access** -- Required access pattern for this file, VipsAccess.
* - **sequential** -- Sequential read only, bool.
* - **fail** -- Fail on first error, bool.
* - **disc** -- Open to disc, bool.
*
* @param filename Filename to load from.
* @param options Set of options.
* @return Output image.
*/
static VImage jp2kload( const char *filename, VOption *options = 0 );
/**
* Load jpeg2000 image.
*
* **Optional parameters**
* - **page** -- Load this page from the image, int.
* - **memory** -- Force open via memory, bool.
* - **access** -- Required access pattern for this file, VipsAccess.
* - **sequential** -- Sequential read only, bool.
* - **fail** -- Fail on first error, bool.
* - **disc** -- Open to disc, bool.
*
* @param buffer Buffer to load from.
* @param options Set of options.
* @return Output image.
*/
static VImage jp2kload_buffer( VipsBlob *buffer, VOption *options = 0 );
/**
* Load jpeg2000 image.
*
* **Optional parameters**
* - **page** -- Load this page from the image, int.
* - **memory** -- Force open via memory, bool.
* - **access** -- Required access pattern for this file, VipsAccess.
* - **sequential** -- Sequential read only, bool.
* - **fail** -- Fail on first error, bool.
* - **disc** -- Open to disc, bool.
*
* @param source Source to load from.
* @param options Set of options.
* @return Output image.
*/
static VImage jp2kload_source( VSource source, VOption *options = 0 );
/**
* Save image in heif format.
*
* **Optional parameters**
* - **tile_width** -- Tile width in pixels, int.
* - **tile_height** -- Tile height in pixels, int.
* - **lossless** -- Enable lossless compression, bool.
* - **Q** -- Q factor, int.
* - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample.
* - **strip** -- Strip all metadata from image, bool.
* - **background** -- Background value, std::vector<double>.
* - **page_height** -- Set page height for multipage save, int.
*
* @param filename Filename to load from.
* @param options Set of options.
*/
void jp2ksave( const char *filename, VOption *options = 0 ) const;
/**
* Save image in heif format.
*
* **Optional parameters**
* - **tile_width** -- Tile width in pixels, int.
* - **tile_height** -- Tile height in pixels, int.
* - **lossless** -- Enable lossless compression, bool.
* - **Q** -- Q factor, int.
* - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample.
* - **strip** -- Strip all metadata from image, bool.
* - **background** -- Background value, std::vector<double>.
* - **page_height** -- Set page height for multipage save, int.
*
* @param options Set of options.
* @return Buffer to save to.
*/
VipsBlob *jp2ksave_buffer( VOption *options = 0 ) const;
/**
* Save image in heif format.
*
* **Optional parameters**
* - **tile_width** -- Tile width in pixels, int.
* - **tile_height** -- Tile height in pixels, int.
* - **lossless** -- Enable lossless compression, bool.
* - **Q** -- Q factor, int.
* - **subsample_mode** -- Select chroma subsample operation mode, VipsForeignSubsample.
* - **strip** -- Strip all metadata from image, bool.
* - **background** -- Background value, std::vector<double>.
* - **page_height** -- Set page height for multipage save, int.
*
* @param target Target to save to.
* @param options Set of options.
*/
void jp2ksave_target( VTarget target, VOption *options = 0 ) const;
/**
* Load jpeg from file.
*
@ -4030,7 +4212,7 @@ VImage msb( VOption *options = 0 ) const;
VImage multiply( VImage right, VOption *options = 0 ) const;
/**
* Load a nifti image.
* Load nifti volume.
*
* **Optional parameters**
* - **memory** -- Force open via memory, bool.
@ -4045,6 +4227,22 @@ VImage multiply( VImage right, VOption *options = 0 ) const;
*/
static VImage niftiload( const char *filename, VOption *options = 0 );
/**
* Load nifti volumes.
*
* **Optional parameters**
* - **memory** -- Force open via memory, bool.
* - **access** -- Required access pattern for this file, VipsAccess.
* - **sequential** -- Sequential read only, bool.
* - **fail** -- Fail on first error, bool.
* - **disc** -- Open to disc, bool.
*
* @param source Source to load from.
* @param options Set of options.
* @return Output image.
*/
static VImage niftiload_source( VSource source, VOption *options = 0 );
/**
* Save image to nifti file.
*
@ -4078,7 +4276,7 @@ static VImage openexrload( const char *filename, VOption *options = 0 );
* Load file with openslide.
*
* **Optional parameters**
* - **attach_associated** -- Attach all asssociated images, bool.
* - **attach_associated** -- Attach all associated images, bool.
* - **level** -- Load this level from the file, int.
* - **autocrop** -- Crop to image bounds, bool.
* - **associated** -- Load this associated image, const char *.
@ -4094,6 +4292,26 @@ static VImage openexrload( const char *filename, VOption *options = 0 );
*/
static VImage openslideload( const char *filename, VOption *options = 0 );
/**
* Load source with openslide.
*
* **Optional parameters**
* - **attach_associated** -- Attach all associated images, bool.
* - **level** -- Load this level from the file, int.
* - **autocrop** -- Crop to image bounds, bool.
* - **associated** -- Load this associated image, const char *.
* - **memory** -- Force open via memory, bool.
* - **access** -- Required access pattern for this file, VipsAccess.
* - **sequential** -- Sequential read only, bool.
* - **fail** -- Fail on first error, bool.
* - **disc** -- Open to disc, bool.
*
* @param source Source to load from.
* @param options Set of options.
* @return Output image.
*/
static VImage openslideload_source( VSource source, VOption *options = 0 );
/**
* Load pdf from file.
*
@ -4171,6 +4389,7 @@ int percent( double percent, VOption *options = 0 ) const;
* **Optional parameters**
* - **cell_size** -- Size of Perlin cells, int.
* - **uchar** -- Output an unsigned char image, bool.
* - **seed** -- Random number seed, int.
*
* @param width Image width in pixels.
* @param height Image height in pixels.
@ -4339,7 +4558,7 @@ static VImage ppmload_source( VSource source, VOption *options = 0 );
* **Optional parameters**
* - **ascii** -- save as ascii, bool.
* - **squash** -- save as one bit, bool.
* - **bitdepth** -- Write as a 1 bit image, int.
* - **bitdepth** -- set to 1 to write as a 1 bit image, int.
* - **strip** -- Strip all metadata from image, bool.
* - **background** -- Background value, std::vector<double>.
* - **page_height** -- Set page height for multipage save, int.
@ -4355,7 +4574,7 @@ void ppmsave( const char *filename, VOption *options = 0 ) const;
* **Optional parameters**
* - **ascii** -- save as ascii, bool.
* - **squash** -- save as one bit, bool.
* - **bitdepth** -- Write as a 1 bit image, int.
* - **bitdepth** -- set to 1 to write as a 1 bit image, int.
* - **strip** -- Strip all metadata from image, bool.
* - **background** -- Background value, std::vector<double>.
* - **page_height** -- Set page height for multipage save, int.
@ -5039,6 +5258,7 @@ static void system( const char *cmd_format, VOption *options = 0 );
* - **width** -- Maximum image width in pixels, int.
* - **height** -- Maximum image height in pixels, int.
* - **align** -- Align on the low, centre or high edge, VipsAlign.
* - **rgba** -- Enable RGBA output, bool.
* - **dpi** -- DPI to render at, int.
* - **justify** -- Justify lines, bool.
* - **spacing** -- Line spacing, int.
@ -5341,7 +5561,23 @@ VImage unpremultiply( VOption *options = 0 ) const;
static VImage vipsload( const char *filename, VOption *options = 0 );
/**
* Save image to vips file.
* Load vips from source.
*
* **Optional parameters**
* - **memory** -- Force open via memory, bool.
* - **access** -- Required access pattern for this file, VipsAccess.
* - **sequential** -- Sequential read only, bool.
* - **fail** -- Fail on first error, bool.
* - **disc** -- Open to disc, bool.
*
* @param source Source to load from.
* @param options Set of options.
* @return Output image.
*/
static VImage vipsload_source( VSource source, VOption *options = 0 );
/**
* Save image to file in vips format.
*
* **Optional parameters**
* - **strip** -- Strip all metadata from image, bool.
@ -5353,6 +5589,19 @@ static VImage vipsload( const char *filename, VOption *options = 0 );
*/
void vipssave( const char *filename, VOption *options = 0 ) const;
/**
* Save image to target in vips format.
*
* **Optional parameters**
* - **strip** -- Strip all metadata from image, bool.
* - **background** -- Background value, std::vector<double>.
* - **page_height** -- Set page height for multipage save, int.
*
* @param target Target to save to.
* @param options Set of options.
*/
void vipssave_target( VTarget target, VOption *options = 0 ) const;
/**
* Load webp from file.
*
@ -5490,6 +5739,7 @@ void webpsave_target( VTarget target, VOption *options = 0 ) const;
*
* **Optional parameters**
* - **cell_size** -- Size of Worley cells, int.
* - **seed** -- Random number seed, int.
*
* @param width Image width in pixels.
* @param height Image height in pixels.

View File

@ -1,5 +1,5 @@
// bodies for vips operations
// Mon 17 Aug 18:04:15 BST 2020
// Wed Apr 21 06:00:31 PM CEST 2021
// this file is generated automatically, do not edit!
VImage VImage::CMC2LCh( VOption *options ) const
@ -1065,6 +1065,18 @@ VImage VImage::fitsload( const char *filename, VOption *options )
return( out );
}
VImage VImage::fitsload_source( VSource source, VOption *options )
{
VImage out;
call( "fitsload_source",
(options ? options : VImage::option())->
set( "out", &out )->
set( "source", source ) );
return( out );
}
void VImage::fitssave( const char *filename, VOption *options ) const
{
call( "fitssave",
@ -1656,6 +1668,70 @@ VImage VImage::join( VImage in2, VipsDirection direction, VOption *options ) con
return( out );
}
VImage VImage::jp2kload( const char *filename, VOption *options )
{
VImage out;
call( "jp2kload",
(options ? options : VImage::option())->
set( "out", &out )->
set( "filename", filename ) );
return( out );
}
VImage VImage::jp2kload_buffer( VipsBlob *buffer, VOption *options )
{
VImage out;
call( "jp2kload_buffer",
(options ? options : VImage::option())->
set( "out", &out )->
set( "buffer", buffer ) );
return( out );
}
VImage VImage::jp2kload_source( VSource source, VOption *options )
{
VImage out;
call( "jp2kload_source",
(options ? options : VImage::option())->
set( "out", &out )->
set( "source", source ) );
return( out );
}
void VImage::jp2ksave( const char *filename, VOption *options ) const
{
call( "jp2ksave",
(options ? options : VImage::option())->
set( "in", *this )->
set( "filename", filename ) );
}
VipsBlob *VImage::jp2ksave_buffer( VOption *options ) const
{
VipsBlob *buffer;
call( "jp2ksave_buffer",
(options ? options : VImage::option())->
set( "in", *this )->
set( "buffer", &buffer ) );
return( buffer );
}
void VImage::jp2ksave_target( VTarget target, VOption *options ) const
{
call( "jp2ksave_target",
(options ? options : VImage::option())->
set( "in", *this )->
set( "target", target ) );
}
VImage VImage::jpegload( const char *filename, VOption *options )
{
VImage out;
@ -2284,6 +2360,18 @@ VImage VImage::niftiload( const char *filename, VOption *options )
return( out );
}
VImage VImage::niftiload_source( VSource source, VOption *options )
{
VImage out;
call( "niftiload_source",
(options ? options : VImage::option())->
set( "out", &out )->
set( "source", source ) );
return( out );
}
void VImage::niftisave( const char *filename, VOption *options ) const
{
call( "niftisave",
@ -2316,6 +2404,18 @@ VImage VImage::openslideload( const char *filename, VOption *options )
return( out );
}
VImage VImage::openslideload_source( VSource source, VOption *options )
{
VImage out;
call( "openslideload_source",
(options ? options : VImage::option())->
set( "out", &out )->
set( "source", source ) );
return( out );
}
VImage VImage::pdfload( const char *filename, VOption *options )
{
VImage out;
@ -3388,6 +3488,18 @@ VImage VImage::vipsload( const char *filename, VOption *options )
return( out );
}
VImage VImage::vipsload_source( VSource source, VOption *options )
{
VImage out;
call( "vipsload_source",
(options ? options : VImage::option())->
set( "out", &out )->
set( "source", source ) );
return( out );
}
void VImage::vipssave( const char *filename, VOption *options ) const
{
call( "vipssave",
@ -3396,6 +3508,14 @@ void VImage::vipssave( const char *filename, VOption *options ) const
set( "filename", filename ) );
}
void VImage::vipssave_target( VTarget target, VOption *options ) const
{
call( "vipssave_target",
(options ? options : VImage::option())->
set( "in", *this )->
set( "target", target ) );
}
VImage VImage::webpload( const char *filename, VOption *options )
{
VImage out;

View File

@ -61,7 +61,6 @@ EXTRA_HFILES=
IGNORE_VIPS_INCLUDE = \
almostdeprecated.h \
cimg_funcs.h \
deprecated.h \
vips7compat.h \
dispatch.h \
@ -127,7 +126,7 @@ HTML_IMAGES = \
# we have some files in markdown ... convert to docbook for gtk-doc
# pandoc makes section headers, we want refsect3 for gtk-doc
.md.xml:
pandoc -s --template="$(realpath pandoc-docbook-template.docbook)" --wrap=none -V title="$<" -f markdown+smart -t docbook-smart -o $@ $<
pandoc -s --template="$(realpath pandoc-docbook-template.docbook)" --wrap=none -V title="$<" -f markdown+smart -t docbook -o $@ $<
sed -e s/section/refsect3/g < $@ > x && mv x $@
# Our markdown source files

View File

@ -19,10 +19,35 @@
<refsect3 xml:id="dont-bind-the-top-level-c-api">
<title>Dont 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.
The libvips C API (vips_add() and so on) was designed to be easy for humans to write. It is inconvenient and dangerous to use from other languages due to its heavy use of varargs.
</para>
<para>
Its much better to use the layer below. This lower layer is structured as create operator, set parameters, execute, extract results. For example, you can execute vips_invert() like this:
Its much better to use the layer below. This lower layer is structured as:
</para>
<itemizedlist>
<listitem>
<para>
Create operator. You can use vips_operation_new() to make a new <literal>VipsOperation</literal> object from an operator nickname, like <literal>&quot;add&quot;</literal>.
</para>
</listitem>
<listitem>
<para>
Set parameters. You can loop over the operation with vips_argument_map() to get the name and type of each input argument. For each argument, you need to get the value from your language, convert to a <literal>GValue</literal>, then use g_object_set_property() to set that value on the operator.
</para>
</listitem>
<listitem>
<para>
Execute with vips_cache_operation_build().
</para>
</listitem>
<listitem>
<para>
Extract results. Again, you loop over the operator arguments with vips_argument_map(), but instead of inputs, this time you look for output arguments. You extract their value with g_object_get_property(), and pass the value back to your language.
</para>
</listitem>
</itemizedlist>
<para>
For example, you can execute vips_invert() like this:
</para>
<programlisting language="c">
/* compile with
@ -111,17 +136,11 @@ main( int argc, char **argv )
return( 0 );
}
</programlisting>
<para>
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 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.
The C++ binding uses this lower layer to define a function called <literal>VImage::call()</literal> which can call any libvips operator with a set of variable arguments.
</para>
<para>
A small Python program walks the set of all libvips operators and generates a set of static bindings. For example:
@ -139,7 +158,7 @@ VImage VImage::invert( VOption *options )
}
</programlisting>
<para>
So from C++ you can call any libvips operator (though without type-safety) with <literal>VImage::call()</literal>, or use the member functions on <literal>VImage</literal> to get type-safe calls for at least the required operator arguments.
So from C++ you can call any libvips operator (though without static typechecking) with <literal>VImage::call()</literal>, or use the member functions on <literal>VImage</literal> to get type-checked calls for at least the required operator arguments.
</para>
<para>
The <literal>VImage</literal> class also adds automatic reference counting, constant expansion, operator overloads, and various other useful features.
@ -151,13 +170,13 @@ VImage VImage::invert( VOption *options )
Languages like Ruby, Python, JavaScript and LuaJIT cant 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.
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. In effect, the binding is generated at runtime.
</para>
</refsect3>
<refsect3 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.
PHP does not have a useful FFI, unfortunately, so for this language a small C 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 xml:id="gobject-introspection">

View File

@ -496,6 +496,11 @@
<entry>Load a fits image</entry>
<entry>vips_fitsload()</entry>
</row>
<row>
<entry>fitsload_source</entry>
<entry>Load fits from a source</entry>
<entry>vips_fitsload_source()</entry>
</row>
<row>
<entry>fitssave</entry>
<entry>Save image to fits file</entry>
@ -558,17 +563,17 @@
</row>
<row>
<entry>gifload</entry>
<entry>Load gif with giflib</entry>
<entry>Load gif with libnsgif</entry>
<entry>vips_gifload()</entry>
</row>
<row>
<entry>gifload_buffer</entry>
<entry>Load gif with giflib</entry>
<entry>Load gif with libnsgif</entry>
<entry>vips_gifload_buffer()</entry>
</row>
<row>
<entry>gifload_source</entry>
<entry>Load gif with giflib</entry>
<entry>Load gif from source</entry>
<entry>vips_gifload_source()</entry>
</row>
<row>
@ -736,6 +741,36 @@
<entry>Join a pair of images</entry>
<entry>vips_join()</entry>
</row>
<row>
<entry>jp2kload</entry>
<entry>Load jpeg2000 image</entry>
<entry>vips_jp2kload()</entry>
</row>
<row>
<entry>jp2kload_buffer</entry>
<entry>Load jpeg2000 image</entry>
<entry>vips_jp2kload_buffer()</entry>
</row>
<row>
<entry>jp2kload_source</entry>
<entry>Load jpeg2000 image</entry>
<entry>vips_jp2kload_source()</entry>
</row>
<row>
<entry>jp2ksave</entry>
<entry>Save image in heif format</entry>
<entry>vips_jp2ksave()</entry>
</row>
<row>
<entry>jp2ksave_buffer</entry>
<entry>Save image in heif format</entry>
<entry>vips_jp2ksave_buffer()</entry>
</row>
<row>
<entry>jp2ksave_target</entry>
<entry>Save image in heif format</entry>
<entry>vips_jp2ksave_target()</entry>
</row>
<row>
<entry>jpegload</entry>
<entry>Load jpeg from file</entry>
@ -973,9 +1008,14 @@
</row>
<row>
<entry>niftiload</entry>
<entry>Load a nifti image</entry>
<entry>Load nifti volume</entry>
<entry>vips_niftiload()</entry>
</row>
<row>
<entry>niftiload_source</entry>
<entry>Load nifti volumes</entry>
<entry>vips_niftiload_source()</entry>
</row>
<row>
<entry>niftisave</entry>
<entry>Save image to nifti file</entry>
@ -991,6 +1031,11 @@
<entry>Load file with openslide</entry>
<entry>vips_openslideload()</entry>
</row>
<row>
<entry>openslideload_source</entry>
<entry>Load source with openslide</entry>
<entry>vips_openslideload_source()</entry>
</row>
<row>
<entry>pdfload</entry>
<entry>Load pdf from file</entry>
@ -1056,11 +1101,21 @@
<entry>Load ppm from file</entry>
<entry>vips_ppmload()</entry>
</row>
<row>
<entry>ppmload_source</entry>
<entry>Load ppm base class</entry>
<entry>vips_ppmload_source()</entry>
</row>
<row>
<entry>ppmsave</entry>
<entry>Save image to ppm file</entry>
<entry>vips_ppmsave()</entry>
</row>
<row>
<entry>ppmsave_target</entry>
<entry>Save to ppm</entry>
<entry>vips_ppmsave_target()</entry>
</row>
<row>
<entry>premultiply</entry>
<entry>Premultiply image alpha</entry>
@ -1426,11 +1481,21 @@
<entry>Load vips from file</entry>
<entry>vips_vipsload()</entry>
</row>
<row>
<entry>vipsload_source</entry>
<entry>Load vips from source</entry>
<entry>vips_vipsload_source()</entry>
</row>
<row>
<entry>vipssave</entry>
<entry>Save image to vips file</entry>
<entry>Save image to file in vips format</entry>
<entry>vips_vipssave()</entry>
</row>
<row>
<entry>vipssave_target</entry>
<entry>Save image to target in vips format</entry>
<entry>vips_vipssave_target()</entry>
</row>
<row>
<entry>webpload</entry>
<entry>Load webp from file</entry>

View File

@ -9,6 +9,10 @@ else
OPTIONAL_DIST_DIR += deprecated
endif
if ENABLE_NSGIF
OPTIONAL_LIB += foreign/libnsgif/libnsgif.la
endif
SUBDIRS = \
include \
foreign \

View File

@ -1,7 +1,7 @@
noinst_LTLIBRARIES = libcolour.la
SUBDIRS = profiles
noinst_LTLIBRARIES = libcolour.la
libcolour_la_SOURCES = \
profiles.c \
profiles.h \

View File

@ -43,6 +43,8 @@
* they can be triggered under normal circumstances
* 17/4/19 kleisauke
* - better rejection of broken embedded profiles
* 29/3/21 [hanssonrickard]
* - add black_point_compensation
*/
/*
@ -155,6 +157,7 @@ typedef struct _VipsIcc {
VipsIntent intent;
VipsPCS pcs;
int depth;
gboolean black_point_compensation;
VipsBlob *in_blob;
cmsHPROFILE in_profile;
@ -218,6 +221,8 @@ vips_icc_build( VipsObject *object )
VipsColourCode *code = (VipsColourCode *) object;
VipsIcc *icc = (VipsIcc *) object;
cmsUInt32Number flags;
if( icc->depth != 8 &&
icc->depth != 16 ) {
vips_error( class->nickname,
@ -356,10 +361,15 @@ vips_icc_build( VipsObject *object )
/* Use cmsFLAGS_NOCACHE to disable the 1-pixel cache and make
* calling cmsDoTransform() from multiple threads safe.
*/
flags = cmsFLAGS_NOCACHE;
if( icc->black_point_compensation )
flags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
if( !(icc->trans = cmsCreateTransform(
icc->in_profile, icc->in_icc_format,
icc->out_profile, icc->out_icc_format,
icc->intent, cmsFLAGS_NOCACHE )) )
icc->intent, flags )) )
return( -1 );
if( VIPS_OBJECT_CLASS( vips_icc_parent_class )->
@ -780,6 +790,13 @@ vips_icc_class_init( VipsIccClass *class )
G_STRUCT_OFFSET( VipsIcc, pcs ),
VIPS_TYPE_PCS, VIPS_PCS_LAB );
VIPS_ARG_BOOL( class, "black_point_compensation", 7,
_( "Black point compensation" ),
_( "Enable black point compensation" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsIcc, black_point_compensation ),
FALSE );
cmsSetLogErrorHandler( icc_error );
}
@ -1411,10 +1428,11 @@ vips_icc_is_compatible_profile( VipsImage *image,
*
* Optional arguments:
*
* * @input_profile: get the input profile from here
* * @intent: transform with this intent
* * @embedded: use profile embedded in input image
* * @pcs: use XYZ or LAB PCS
* * @pcs: #VipsPCS, use XYZ or LAB PCS
* * @intent: #VipsIntent, transform with this intent
* * @black_point_compensation: %gboolean, enable black point compensation
* * @embedded: %gboolean, use profile embedded in input image
* * @input_profile: %gchararray, get the input profile from here
*
* Import an image from device space to D65 LAB with an ICC profile. If @pcs is
* set to #VIPS_PCS_XYZ, use CIE XYZ PCS instead.
@ -1431,6 +1449,9 @@ vips_icc_is_compatible_profile( VipsImage *image,
* @input_profile. If @input_profile is not supplied, the
* metadata profile, if any, is used as a fall-back.
*
* If @black_point_compensation is set, LCMS black point compensation is
* enabled.
*
* Returns: 0 on success, -1 on error.
*/
int
@ -1454,10 +1475,11 @@ vips_icc_import( VipsImage *in, VipsImage **out, ... )
*
* Optional arguments:
*
* * @intent: transform with this intent
* * @depth: depth of output image in bits
* * @output_profile: get the output profile from here
* * @pcs: use XYZ or LAB PCS
* * @pcs: #VipsPCS, use XYZ or LAB PCS
* * @intent: #VipsIntent, transform with this intent
* * @black_point_compensation: %gboolean, enable black point compensation
* * @output_profile: %gchararray, get the output profile from here
* * @depth: %gint, depth of output image in bits
*
* Export an image from D65 LAB to device space with an ICC profile.
* If @pcs is
@ -1466,6 +1488,9 @@ vips_icc_import( VipsImage *in, VipsImage **out, ... )
* If @output_profile is set, export with that and attach it to the output
* image.
*
* If @black_point_compensation is set, LCMS black point compensation is
* enabled.
*
* Returns: 0 on success, -1 on error.
*/
int
@ -1490,10 +1515,12 @@ vips_icc_export( VipsImage *in, VipsImage **out, ... )
*
* Optional arguments:
*
* * @input_profile: get the input profile from here
* * @intent: transform with this intent
* * @depth: depth of output image in bits
* * @embedded: use profile embedded in input image
* * @pcs: #VipsPCS, use XYZ or LAB PCS
* * @intent: #VipsIntent, transform with this intent
* * @black_point_compensation: %gboolean, enable black point compensation
* * @embedded: %gboolean, use profile embedded in input image
* * @input_profile: %gchararray, get the input profile from here
* * @depth: %gint, depth of output image in bits
*
* Transform an image with a pair of ICC profiles. The input image is moved to
* profile-connection space with the input profile and then to the output
@ -1511,6 +1538,9 @@ vips_icc_export( VipsImage *in, VipsImage **out, ... )
* @input_profile. If @input_profile is not supplied, the
* metadata profile, if any, is used as a fall-back.
*
* If @black_point_compensation is set, LCMS black point compensation is
* enabled.
*
* The output image has the output profile attached to the #VIPS_META_ICC_NAME
* field.
*

View File

@ -32143,6 +32143,64 @@ static VipsProfileFallback vips__profile_fallback_cmyk = {
}
};
static VipsProfileFallback vips__profile_fallback_p3 = {
"p3",
736,
{
0x78, 0xDA, 0x7D, 0xD0, 0x03, 0xA0, 0xE4, 0x30, 0x14, 0x05, 0xD0, 0x57,
0x7C, 0xDB, 0xB6, 0x6D, 0xDB, 0xB6, 0x8D, 0xB1, 0xD1, 0xCE, 0xDA, 0xB6,
0x6D, 0xDB, 0xB6, 0x6D, 0xDB, 0xB6, 0xED, 0x74, 0xED, 0x5B, 0x9D, 0xC6,
0x09, 0x00, 0x7E, 0x49, 0xCC, 0x92, 0x50, 0xB8, 0x21, 0x80, 0x44, 0x4A,
0x2B, 0x8B, 0x33, 0x92, 0x1D, 0x2B, 0xAB, 0xAA, 0x1D, 0x35, 0xAE, 0x00,
0x01, 0xA6, 0xA0, 0x05, 0xFA, 0x60, 0xD7, 0xC4, 0xA2, 0xE4, 0x79, 0x25,
0xE9, 0xA5, 0x80, 0x42, 0x35, 0xB5, 0xA4, 0x58, 0xB4, 0x52, 0x0C, 0xBF,
0xE4, 0xC5, 0x09, 0xC0, 0x98, 0xEF, 0x51, 0x3F, 0x7E, 0x93, 0x94, 0xDD,
0x56, 0x66, 0xB0, 0xF7, 0x52, 0x5A, 0x52, 0x78, 0x42, 0x41, 0x6A, 0xD8,
0x5E, 0xEB, 0x1E, 0x56, 0xF0, 0xFF, 0x68, 0xB1, 0x39, 0x14, 0x0B, 0x7D,
0x1F, 0xA1, 0xA7, 0x9E, 0x25, 0x57, 0xD2, 0x00, 0x98, 0x2E, 0xB2, 0x6E,
0x4B, 0x5A, 0xCE, 0xD8, 0x12, 0xD9, 0x54, 0x89, 0x16, 0x85, 0xEC, 0xCB,
0x98, 0xF7, 0xC5, 0x89, 0x8C, 0x9B, 0xBF, 0xB8, 0x94, 0xB1, 0xB2, 0xB4,
0x38, 0x05, 0x99, 0x8F, 0x9E, 0x56, 0xBC, 0x9F, 0xDC, 0xFC, 0x93, 0xBF,
0xCE, 0xC5, 0x44, 0x8D, 0x2A, 0x0C, 0x41, 0xE5, 0x3F, 0x42, 0x73, 0x5A,
0xD1, 0xCC, 0x37, 0x25, 0x25, 0x10, 0x98, 0x33, 0xF8, 0x52, 0xFA, 0xB4,
0x08, 0x30, 0xF4, 0xC1, 0xCC, 0xF7, 0xFD, 0x28, 0xEB, 0x7A, 0x11, 0x20,
0x6E, 0x23, 0xA3, 0x1F, 0x65, 0xD9, 0xE8, 0x7F, 0x71, 0x04, 0x80, 0xF6,
0xF2, 0x1F, 0x65, 0x9E, 0x91, 0x00, 0x46, 0xDA, 0x00, 0xBB, 0x5A, 0xB1,
0x54, 0xCA, 0x16, 0xF0, 0x25, 0x2B, 0xD0, 0x63, 0x0B, 0x91, 0x50, 0x0A,
0x72, 0xE8, 0x07, 0xB3, 0x60, 0x1B, 0x5C, 0xC6, 0x00, 0x73, 0xC6, 0xD2,
0x31, 0x09, 0x36, 0x1C, 0xDB, 0x8C, 0x3D, 0xC2, 0x1D, 0xF1, 0x32, 0xBC,
0x2F, 0xBE, 0x8D, 0xC0, 0x88, 0x04, 0xA2, 0x0B, 0xB1, 0x83, 0xD4, 0x27,
0xAB, 0xC8, 0x99, 0xE4, 0x6B, 0xB5, 0x5C, 0xB5, 0x69, 0x6A, 0x1F, 0xD4,
0x6B, 0xD5, 0x37, 0x68, 0x38, 0x69, 0xF4, 0xD1, 0x78, 0xA6, 0xC9, 0xD2,
0x3C, 0xAE, 0x95, 0xA5, 0xB5, 0x55, 0x3B, 0x41, 0x7B, 0xA3, 0x4E, 0xB2,
0xCE, 0x6E, 0xDD, 0x52, 0xDD, 0xCB, 0x7A, 0xB4, 0xBE, 0x96, 0xFE, 0x14,
0x83, 0x44, 0x83, 0x4B, 0x86, 0xDD, 0x8D, 0xFC, 0x8C, 0xCE, 0x18, 0xF7,
0x31, 0x89, 0x37, 0x79, 0x61, 0xBA, 0xC4, 0x4C, 0x61, 0x1E, 0x6E, 0xFE,
0xDE, 0x62, 0x8F, 0xE5, 0x68, 0x2B, 0xA9, 0x75, 0xBA, 0x8D, 0xB3, 0x2D,
0x61, 0x7B, 0xD3, 0xEE, 0x90, 0xFD, 0x7A, 0x87, 0x05, 0x8E, 0xD3, 0x9C,
0x26, 0x38, 0x8F, 0x73, 0x99, 0xE8, 0x3A, 0xDD, 0x6D, 0xB1, 0xFB, 0x26,
0x8F, 0xE3, 0x9E, 0xF7, 0xBD, 0xB5, 0x7D, 0x7C, 0x7C, 0x8B, 0xFC, 0xDA,
0xF9, 0xCF, 0x09, 0xB8, 0x10, 0x64, 0x1E, 0x5C, 0x1C, 0x32, 0x2C, 0xF4,
0x74, 0xB8, 0x6B, 0x04, 0x15, 0xB9, 0x23, 0xDA, 0x31, 0xA6, 0x5D, 0xEC,
0xC5, 0xF8, 0xB4, 0x84, 0x45, 0x49, 0x4E, 0xC9, 0x23, 0x52, 0x0D, 0xD3,
0x06, 0x66, 0x18, 0x67, 0x8E, 0xCD, 0xF6, 0xCC, 0x59, 0x9B, 0x57, 0x94,
0xFF, 0xA0, 0x70, 0x60, 0x71, 0x58, 0xC9, 0xA5, 0xB2, 0x41, 0x15, 0x69,
0x55, 0x50, 0xBD, 0xA1, 0xB6, 0x5B, 0x7D, 0x6E, 0xA3, 0x4D, 0xD3, 0x43,
0xD6, 0x4E, 0xCE, 0x0C, 0x5E, 0x6F, 0x81, 0x42, 0xD4, 0x20, 0x29, 0x92,
0x65, 0x2B, 0xD2, 0xA9, 0x6C, 0x55, 0x51, 0xCB, 0xFA, 0xD6, 0x8A, 0xB6,
0xBD, 0xDA, 0xCF, 0xE8, 0xB8, 0xAB, 0xF3, 0xA3, 0x6E, 0xF6, 0x3D, 0x0A,
0x7B, 0xF5, 0xEE, 0xB3, 0xBD, 0xBF, 0xD6, 0xC0, 0xA2, 0xC1, 0x13, 0x87,
0x3E, 0x1D, 0x91, 0x33, 0x6A, 0xEE, 0x58, 0xFD, 0xF1, 0xAD, 0x26, 0xDE,
0x9C, 0x52, 0x33, 0xED, 0xC4, 0xCC, 0xF2, 0xD9, 0x67, 0xE7, 0xF1, 0x16,
0xBC, 0x5C, 0x3C, 0x70, 0x99, 0xF7, 0x8A, 0x7D, 0xAB, 0xE9, 0x75, 0x4E,
0x1B, 0x8E, 0x6F, 0xEE, 0xBF, 0x2D, 0x77, 0xA7, 0xE1, 0xEE, 0x33, 0xFB,
0xE6, 0x1E, 0xEC, 0x78, 0xA4, 0xF6, 0x78, 0xDC, 0x29, 0xD7, 0xB3, 0xC6,
0x17, 0xC8, 0x4B, 0x1F, 0xAE, 0xBE, 0xBB, 0x89, 0xDD, 0xD1, 0xBD, 0x6F,
0xFB, 0x28, 0xF4, 0x69, 0xE1, 0x0B, 0xEA, 0xF5, 0xD8, 0x77, 0x7B, 0x3E,
0x7E, 0xFC, 0x04, 0xD4, 0xCA, 0xD2, 0x46,
}
};
static VipsProfileFallback vips__profile_fallback_sRGB = {
"sRGB",
6922,
@ -32348,6 +32406,7 @@ static VipsProfileFallback vips__profile_fallback_sRGB = {
VipsProfileFallback *vips__profile_fallback_table[] = {
&vips__profile_fallback_cmyk,
&vips__profile_fallback_p3,
&vips__profile_fallback_sRGB,
NULL
};

View File

@ -1,3 +1,4 @@
EXTRA_DIST = \
p3.icm \
cmyk.icm \
sRGB.icm

Binary file not shown.

View File

@ -55,13 +55,17 @@
#include <stdio.h>
#include <string.h>
#if _MSC_VER
#ifdef _MSC_VER
#include <cstdlib>
#else
#include <stdlib.h>
#endif
#include <math.h>
#if defined(HAVE__ALIGNED_MALLOC) || defined(HAVE_MEMALIGN)
#include <malloc.h>
#endif
#include <vips/vips.h>
#include <vips/internal.h>
#include <vips/debug.h>
@ -81,7 +85,7 @@
#ifdef HAVE_VECTOR_ARITH
/* A vector of four floats.
*/
typedef float v4f __attribute__((vector_size(4 * sizeof(float))));
typedef float v4f __attribute__((vector_size(4 * sizeof(float)),aligned(16)));
#endif /*HAVE_VECTOR_ARITH*/
typedef struct _VipsCompositeBase {
@ -130,12 +134,6 @@ typedef struct _VipsCompositeBase {
*/
gboolean skippable;
#ifdef HAVE_VECTOR_ARITH
/* max_band as a vector, for the RGBA case.
*/
v4f max_band_vec;
#endif /*HAVE_VECTOR_ARITH*/
} VipsCompositeBase;
typedef VipsConversionClass VipsCompositeBaseClass;
@ -168,6 +166,14 @@ vips_composite_base_dispose( GObject *gobject )
/* Our sequence value.
*/
typedef struct {
#ifdef HAVE_VECTOR_ARITH
/* max_band as a vector, for the RGBA case. This must be
* defined first to ensure that the member is aligned
* on a 16-byte boundary.
*/
v4f max_band_vec;
#endif /*HAVE_VECTOR_ARITH*/
VipsCompositeBase *composite;
/* Full set of input regions, each made on the corresponding input
@ -196,6 +202,39 @@ typedef struct {
} VipsCompositeSequence;
#ifdef HAVE_VECTOR_ARITH
/* Allocate aligned memory. The return value can be released
* by calling the vips_free_aligned() function, for example:
* VIPS_FREEF( vips_free_aligned, ptr );
*/
static inline void *
vips_alloc_aligned( size_t sz, size_t align )
{
g_assert( !(align & (align - 1)) );
#ifdef HAVE__ALIGNED_MALLOC
return _aligned_malloc( sz, align );
#elif defined(HAVE_POSIX_MEMALIGN)
void *ptr;
if( posix_memalign( &ptr, align, sz ) ) return NULL;
return ptr;
#elif defined(HAVE_MEMALIGN)
return memalign( align, sz );
#else
#error Missing aligned alloc implementation
#endif
}
static inline void
vips_free_aligned( void* ptr )
{
#ifdef HAVE__ALIGNED_MALLOC
_aligned_free( ptr );
#else /*defined(HAVE_POSIX_MEMALIGN) || defined(HAVE_MEMALIGN)*/
free( ptr );
#endif
}
#endif /*HAVE_VECTOR_ARITH*/
static int
vips_composite_stop( void *vseq, void *a, void *b )
{
@ -216,7 +255,11 @@ vips_composite_stop( void *vseq, void *a, void *b )
VIPS_FREE( seq->enabled );
VIPS_FREE( seq->p );
#ifdef HAVE_VECTOR_ARITH
VIPS_FREEF( vips_free_aligned, seq );
#else /*!defined(HAVE_VECTOR_ARITH)*/
VIPS_FREE( seq );
#endif /*HAVE_VECTOR_ARITH*/
return( 0 );
}
@ -230,7 +273,14 @@ vips_composite_start( VipsImage *out, void *a, void *b )
VipsCompositeSequence *seq;
int i, n;
#ifdef HAVE_VECTOR_ARITH
/* Ensure that the memory is aligned on a 16-byte boundary.
*/
if( !(seq = ((VipsCompositeSequence *) vips_alloc_aligned(
sizeof( VipsCompositeSequence ), 16 ))) )
#else /*!defined(HAVE_VECTOR_ARITH)*/
if( !(seq = VIPS_NEW( NULL, VipsCompositeSequence )) )
#endif /*HAVE_VECTOR_ARITH*/
return( NULL );
seq->composite = composite;
@ -280,7 +330,19 @@ vips_composite_start( VipsImage *out, void *a, void *b )
return( NULL );
}
}
#ifdef HAVE_VECTOR_ARITH
/* We need a float version for the vector path.
*/
if( composite->bands == 3 )
seq->max_band_vec = (v4f){
(float) composite->max_band[0],
(float) composite->max_band[1],
(float) composite->max_band[2],
(float) composite->max_band[3]
};
#endif
return( seq );
}
@ -664,9 +726,11 @@ vips_composite_base_blend( VipsCompositeBase *composite,
*/
template <typename T>
static void
vips_composite_base_blend3( VipsCompositeBase *composite,
vips_composite_base_blend3( VipsCompositeSequence *seq,
VipsBlendMode mode, v4f &B, T * restrict p )
{
VipsCompositeBase *composite = seq->composite;
v4f A;
float aA;
float aB;
@ -684,7 +748,7 @@ vips_composite_base_blend3( VipsCompositeBase *composite,
A[2] = p[2];
A[3] = p[3];
A /= composite->max_band_vec;
A /= seq->max_band_vec;
aA = A[3];
aB = B[3];
@ -975,7 +1039,7 @@ vips_combine_pixels3( VipsCompositeSequence *seq, VipsPel *q )
/* Scale the base pixel to 0 - 1.
*/
B /= composite->max_band_vec;
B /= seq->max_band_vec;
aB = B[3];
if( !composite->premultiplied ) {
@ -987,7 +1051,7 @@ vips_combine_pixels3( VipsCompositeSequence *seq, VipsPel *q )
int j = seq->enabled[i];
VipsBlendMode m = n_mode == 1 ? mode[0] : mode[j - 1];
vips_composite_base_blend3<T>( composite, m, B, tp[i] );
vips_composite_base_blend3<T>( seq, m, B, tp[i] );
}
/* Unpremultiply, if necessary.
@ -1006,7 +1070,7 @@ vips_combine_pixels3( VipsCompositeSequence *seq, VipsPel *q )
/* Write back as a full range pixel, clipping to range.
*/
B *= composite->max_band_vec;
B *= seq->max_band_vec;
if( min_T != 0 ||
max_T != 0 ) {
float low = min_T;
@ -1386,14 +1450,6 @@ vips_composite_base_build( VipsObject *object )
return( -1 );
}
#ifdef HAVE_VECTOR_ARITH
/* We need a float version for the vector path.
*/
if( composite->bands == 3 )
for( int b = 0; b <= 3; b++ )
composite->max_band_vec[b] = composite->max_band[b];
#endif /*HAVE_VECTOR_ARITH*/
/* Transform the input images to match in format. We may have
* mixed float and double, for example.
*/

View File

@ -116,9 +116,9 @@ vips_create_operation_init( void )
extern GType vips_gaussmat_get_type( void );
extern GType vips_logmat_get_type( void );
extern GType vips_gaussnoise_get_type( void );
#ifdef HAVE_PANGOFT2
#ifdef HAVE_PANGOCAIRO
extern GType vips_text_get_type( void );
#endif /*HAVE_PANGOFT2*/
#endif /*HAVE_PANGOCAIRO*/
extern GType vips_xyz_get_type( void );
extern GType vips_eye_get_type( void );
extern GType vips_grey_get_type( void );
@ -146,9 +146,9 @@ vips_create_operation_init( void )
vips_gaussmat_get_type();
vips_logmat_get_type();
vips_gaussnoise_get_type();
#ifdef HAVE_PANGOFT2
#ifdef HAVE_PANGOCAIRO
vips_text_get_type();
#endif /*HAVE_PANGOFT2*/
#endif /*HAVE_PANGOCAIRO*/
vips_xyz_get_type();
vips_eye_get_type();
vips_grey_get_type();

View File

@ -32,6 +32,9 @@
* - fitting could occasionally terminate early [levmorozov]
* 16/5/20 [keiviv]
* - don't add fontfiles repeatedly
* 12/4/21
* - switch to cairo for text rendering
* - add rgba flag
*/
/*
@ -74,11 +77,17 @@
#include <string.h>
#include <vips/vips.h>
#include <vips/internal.h>
#ifdef HAVE_PANGOFT2
#ifdef HAVE_PANGOCAIRO
#include <cairo.h>
#include <pango/pango.h>
#include <pango/pangoft2.h>
#include <pango/pangocairo.h>
#ifdef HAVE_FONTCONFIG
#include <fontconfig/fontconfig.h>
#endif
#include "pcreate.h"
@ -94,8 +103,8 @@ typedef struct _VipsText {
gboolean justify;
int dpi;
char *fontfile;
gboolean rgba;
FT_Bitmap bitmap;
PangoContext *context;
PangoLayout *layout;
@ -129,7 +138,6 @@ vips_text_dispose( GObject *gobject )
VIPS_UNREF( text->layout );
VIPS_UNREF( text->context );
VIPS_FREE( text->bitmap.buffer );
G_OBJECT_CLASS( vips_text_parent_class )->dispose( gobject );
}
@ -186,8 +194,8 @@ vips_text_get_extents( VipsText *text, VipsRect *extents )
PangoRectangle ink_rect;
PangoRectangle logical_rect;
pango_ft2_font_map_set_resolution(
PANGO_FT2_FONT_MAP( vips_text_fontmap ), text->dpi, text->dpi );
pango_cairo_font_map_set_resolution(
PANGO_CAIRO_FONT_MAP( vips_text_fontmap ), text->dpi );
VIPS_UNREF( text->layout );
if( !(text->layout = text_layout_new( text->context,
@ -340,9 +348,12 @@ vips_text_build( VipsObject *object )
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsCreate *create = VIPS_CREATE( object );
VipsText *text = (VipsText *) object;
VipsImage **t = (VipsImage **) vips_object_local_array( object, 3 );
VipsRect extents;
int y;
VipsImage *image;
cairo_surface_t *surface;
cairo_t *cr;
if( VIPS_OBJECT_CLASS( vips_text_parent_class )->build( object ) )
return( -1 );
@ -356,7 +367,8 @@ vips_text_build( VipsObject *object )
g_mutex_lock( vips_text_lock );
if( !vips_text_fontmap )
vips_text_fontmap = pango_ft2_font_map_new();
vips_text_fontmap = pango_cairo_font_map_new();
if( !vips_text_fontfiles )
vips_text_fontfiles =
g_hash_table_new( g_str_hash, g_str_equal );
@ -364,20 +376,25 @@ vips_text_build( VipsObject *object )
text->context = pango_font_map_create_context(
PANGO_FONT_MAP( vips_text_fontmap ) );
#ifdef HAVE_FONTCONFIG
if( text->fontfile &&
!g_hash_table_lookup( vips_text_fontfiles, text->fontfile ) ) {
/* This can fail if you eg. add the same font from two
* different files. Just warn.
*/
if( !FcConfigAppFontAddFile( NULL,
(const FcChar8 *) text->fontfile ) ) {
vips_error( class->nickname,
_( "unable to load font \"%s\"" ),
(const FcChar8 *) text->fontfile ) )
g_warning( _( "unable to load fontfile \"%s\"" ),
text->fontfile );
g_mutex_unlock( vips_text_lock );
return( -1 );
}
g_hash_table_insert( vips_text_fontfiles,
text->fontfile,
g_strdup( text->fontfile ) );
}
#else /*!HAVE_FONTCONFIG*/
if( text->fontfile )
g_warning( "%s",
_( "ignoring fontfile (no fontconfig support)" ) );
#endif /*HAVE_FONTCONFIG*/
/* If our caller set height and not dpi, we adjust dpi until
* we get a fit.
@ -399,40 +416,65 @@ vips_text_build( VipsObject *object )
return( -1 );
}
text->bitmap.width = extents.width;
text->bitmap.pitch = (text->bitmap.width + 3) & ~3;
text->bitmap.rows = extents.height;
if( !(text->bitmap.buffer =
VIPS_ARRAY( NULL,
text->bitmap.pitch * text->bitmap.rows, VipsPel )) ) {
/* Set DPI as pixels/mm.
*/
image = t[0] = vips_image_new_memory();
vips_image_init_fields( image,
extents.width, extents.height, 4,
VIPS_FORMAT_UCHAR, VIPS_CODING_NONE,
VIPS_INTERPRETATION_sRGB,
text->dpi / 25.4, text->dpi / 25.4 );
vips_image_pipelinev( image, VIPS_DEMAND_STYLE_ANY, NULL );
image->Xoffset = extents.left;
image->Yoffset = extents.top;
if( vips_image_write_prepare( image ) ) {
g_mutex_unlock( vips_text_lock );
return( -1 );
}
text->bitmap.num_grays = 256;
text->bitmap.pixel_mode = ft_pixel_mode_grays;
memset( text->bitmap.buffer, 0x00,
text->bitmap.pitch * text->bitmap.rows );
pango_ft2_render_layout( &text->bitmap, text->layout,
-extents.left, -extents.top );
surface = cairo_image_surface_create_for_data(
VIPS_IMAGE_ADDR( image, 0, 0 ),
CAIRO_FORMAT_ARGB32,
image->Xsize, image->Ysize,
VIPS_IMAGE_SIZEOF_LINE( image ) );
cr = cairo_create( surface );
cairo_surface_destroy( surface );
cairo_translate( cr, -extents.left, -extents.top );
pango_cairo_show_layout( cr, text->layout );
cairo_destroy( cr );
g_mutex_unlock( vips_text_lock );
vips_image_init_fields( create->out,
text->bitmap.width, text->bitmap.rows, 1,
VIPS_FORMAT_UCHAR, VIPS_CODING_NONE,
VIPS_INTERPRETATION_MULTIBAND,
1.0, 1.0 );
vips_image_pipelinev( create->out,
VIPS_DEMAND_STYLE_ANY, NULL );
create->out->Xoffset = extents.left;
create->out->Yoffset = extents.top;
if( text->rgba ) {
int y;
for( y = 0; y < text->bitmap.rows; y++ )
if( vips_image_write_line( create->out, y,
(VipsPel *) text->bitmap.buffer +
y * text->bitmap.pitch ) )
/* Cairo makes pre-multipled BRGA -- we must byteswap and
* unpremultiply.
*/
for( y = 0; y < image->Ysize; y++ )
vips__premultiplied_bgra2rgba(
(guint32 *)
VIPS_IMAGE_ADDR( image, 0, y ),
image->Xsize );
}
else {
/* We just want the alpha channel.
*/
if( vips_extract_band( image, &t[1], 3, NULL ) ||
vips_copy( t[1], &t[2],
"interpretation", VIPS_INTERPRETATION_MULTIBAND,
NULL ) )
return( -1 );
image = t[2];
}
if( vips_image_write( image, create->out ) )
return( -1 );
return( 0 );
}
@ -534,6 +576,13 @@ vips_text_class_init( VipsTextClass *class )
G_STRUCT_OFFSET( VipsText, fontfile ),
NULL );
VIPS_ARG_BOOL( class, "rgba", 9,
_( "RGBA" ),
_( "Enable RGBA output" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsText, rgba ),
FALSE );
}
static void
@ -541,11 +590,10 @@ vips_text_init( VipsText *text )
{
text->align = VIPS_ALIGN_LOW;
text->dpi = 72;
text->bitmap.buffer = NULL;
VIPS_SETSTR( text->font, "sans 12" );
}
#endif /*HAVE_PANGOFT2*/
#endif /*HAVE_PANGOCAIRO*/
/**
* vips_text:
@ -563,17 +611,22 @@ vips_text_init( VipsText *text )
* * @justify: %gboolean, justify lines
* * @dpi: %gint, render at this resolution
* * @autofit_dpi: %gint, read out auto-fitted DPI
* * @rgba: %gboolean, enable RGBA output
* * @spacing: %gint, space lines by this in points
*
* Draw the string @text to an image. @out is a one-band 8-bit
* Draw the string @text to an image. @out is normally a one-band 8-bit
* unsigned char image, with 0 for no text and 255 for text. Values between
* are used for anti-aliasing.
*
* Set @rgba to enable RGBA output. This is useful for colour emoji rendering,
* or support for pango markup features like `<span
* foreground="red">Red!</span>`.
*
* @text is the text to render as a UTF-8 string. It can contain Pango markup,
* for example "&lt;i&gt;The&lt;/i&gt;Guardian".
* for example `<i>The</i>Guardian`.
*
* @font is the font to render with, as a fontconfig name. Examples might be
* "sans 12" or perhaps "bitstream charter bold 10".
* `sans 12` or perhaps `bitstream charter bold 10`.
*
* You can specify a font to load with @fontfile. You'll need to also set the
* name of the font with @font.

View File

@ -1,72 +1,78 @@
if ENABLE_NSGIF
SUBDIRS = libnsgif
endif
noinst_LTLIBRARIES = libforeign.la
libforeign_la_SOURCES = \
pforeign.h \
heifload.c \
heifsave.c \
niftiload.c \
niftisave.c \
quantise.c \
exif.c \
gifload.c \
analyze2vips.c \
analyzeload.c \
cairo.c \
pdfload.c \
pdfiumload.c \
svgload.c \
radiance.c \
radload.c \
radsave.c \
ppmload.c \
ppmsave.c \
csvload.c \
csvsave.c \
matrixload.c \
matrixsave.c \
dzsave.c \
rawload.c \
rawsave.c \
vipsload.c \
vipssave.c \
dbh.h \
analyzeload.c \
analyze2vips.c \
foreign.c \
matlab.c \
matload.c \
magick.h \
magick.c \
magick2vips.c \
magickload.c \
magick7load.c \
magicksave.c \
spngload.c \
pngload.c \
pngsave.c \
vipspng.c \
openexr2vips.c \
openexrload.c \
dzsave.c \
exif.c \
fits.c \
fitsload.c \
fitssave.c \
tiff.h \
tiff.c \
vips2tiff.c \
tiff2vips.c \
tiffload.c \
tiffsave.c \
openslide2vips.c \
openslideload.c \
webpload.c \
webpsave.c \
webp2vips.c \
vips2webp.c \
vips2jpeg.c \
foreign.c \
heifload.c \
heifsave.c \
jp2kload.c \
jp2ksave.c \
jpeg2vips.c \
jpeg.h \
jpegload.c \
jpegsave.c
jpegsave.c \
magick2vips.c \
magick7load.c \
magick.c \
magick.h \
magickload.c \
magicksave.c \
matlab.c \
matload.c \
matrixload.c \
matrixsave.c \
niftiload.c \
niftisave.c \
nsgifload.c \
openexr2vips.c \
openexrload.c \
openslide2vips.c \
openslideload.c \
pdfiumload.c \
pdfload.c \
pforeign.h \
pngload.c \
pngsave.c \
ppmload.c \
ppmsave.c \
quantise.c \
radiance.c \
radload.c \
radsave.c \
rawload.c \
rawsave.c \
spngload.c \
svgload.c \
tiff2vips.c \
tiff.c \
tiff.h \
tiffload.c \
tiffsave.c \
vips2jpeg.c \
vips2tiff.c \
vips2webp.c \
vipsload.c \
vipspng.c \
vipssave.c \
webp2vips.c \
webpload.c \
webpsave.c
EXTRA_DIST =
EXTRA_DIST = libnsgif
AM_CPPFLAGS = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@

View File

@ -366,7 +366,8 @@ vips_gsf_path( VipsGsfDirectory *tree, const char *name, ... )
* path we are creating.
*/
tree->file_count += 1;
tree->filename_lengths += strlen( tree->out->name ) + strlen( name ) + 1;
tree->filename_lengths +=
strlen( tree->out->name ) + strlen( name ) + 1;
dir = tree;
va_start( ap, name );

View File

@ -2176,6 +2176,13 @@ vips_foreign_operation_init( void )
extern GType vips_foreign_load_svg_buffer_get_type( void );
extern GType vips_foreign_load_svg_source_get_type( void );
extern GType vips_foreign_load_jp2k_file_get_type( void );
extern GType vips_foreign_load_jp2k_buffer_get_type( void );
extern GType vips_foreign_load_jp2k_source_get_type( void );
extern GType vips_foreign_save_jp2k_file_get_type( void );
extern GType vips_foreign_save_jp2k_buffer_get_type( void );
extern GType vips_foreign_save_jp2k_target_get_type( void );
extern GType vips_foreign_load_heif_file_get_type( void );
extern GType vips_foreign_load_heif_buffer_get_type( void );
extern GType vips_foreign_load_heif_source_get_type( void );
@ -2187,22 +2194,25 @@ vips_foreign_operation_init( void )
extern GType vips_foreign_load_nifti_source_get_type( void );
extern GType vips_foreign_save_nifti_get_type( void );
extern GType vips_foreign_load_gif_file_get_type( void );
extern GType vips_foreign_load_gif_buffer_get_type( void );
extern GType vips_foreign_load_gif_source_get_type( void );
extern GType vips_foreign_load_nsgif_file_get_type( void );
extern GType vips_foreign_load_nsgif_buffer_get_type( void );
extern GType vips_foreign_load_nsgif_source_get_type( void );
vips_foreign_load_csv_file_get_type();
vips_foreign_load_csv_source_get_type();
vips_foreign_save_csv_file_get_type();
vips_foreign_save_csv_target_get_type();
vips_foreign_load_matrix_file_get_type();
vips_foreign_load_matrix_source_get_type();
vips_foreign_save_matrix_file_get_type();
vips_foreign_save_matrix_target_get_type();
vips_foreign_print_matrix_get_type();
vips_foreign_load_raw_get_type();
vips_foreign_save_raw_get_type();
vips_foreign_save_raw_fd_get_type();
vips_foreign_load_vips_file_get_type();
vips_foreign_load_vips_source_get_type();
vips_foreign_save_vips_file_get_type();
@ -2246,11 +2256,20 @@ vips_foreign_operation_init( void )
vips_foreign_load_svg_source_get_type();
#endif /*HAVE_RSVG*/
#ifdef HAVE_GIFLIB
vips_foreign_load_gif_file_get_type();
vips_foreign_load_gif_buffer_get_type();
vips_foreign_load_gif_source_get_type();
#endif /*HAVE_GIFLIB*/
#ifdef HAVE_LIBOPENJP2
vips_foreign_load_jp2k_file_get_type();
vips_foreign_load_jp2k_buffer_get_type();
vips_foreign_load_jp2k_source_get_type();
vips_foreign_save_jp2k_file_get_type();
vips_foreign_save_jp2k_buffer_get_type();
vips_foreign_save_jp2k_target_get_type();
#endif /*HAVE_LIBOPENJP2*/
#ifdef HAVE_NSGIF
vips_foreign_load_nsgif_file_get_type();
vips_foreign_load_nsgif_buffer_get_type();
vips_foreign_load_nsgif_source_get_type();
#endif /*HAVE_NSGIF*/
#ifdef HAVE_GSF
vips_foreign_save_dz_file_get_type();

File diff suppressed because it is too large Load Diff

View File

@ -230,7 +230,8 @@ vips_foreign_load_heif_build( VipsObject *object )
printf( "vips_foreign_load_heif_build:\n" );
#endif /*DEBUG*/
if( vips_source_rewind( heif->source ) )
if( heif->source &&
vips_source_rewind( heif->source ) )
return( -1 );
if( !heif->ctx ) {
@ -245,7 +246,6 @@ vips_foreign_load_heif_build( VipsObject *object )
}
}
if( VIPS_OBJECT_CLASS( vips_foreign_load_heif_parent_class )->
build( object ) )
return( -1 );
@ -253,7 +253,6 @@ vips_foreign_load_heif_build( VipsObject *object )
return( 0 );
}
static const char *heif_magic[] = {
"ftypheic", /* A regular heif image */
"ftypheix", /* Extended range (>8 bit) image */

View File

@ -321,6 +321,7 @@ vips_foreign_save_heif_build( VipsObject *object )
VipsForeignSave *save = (VipsForeignSave *) object;
VipsForeignSaveHeif *heif = (VipsForeignSaveHeif *) object;
const char *filename;
struct heif_error error;
struct heif_writer writer;
char *chroma;
@ -335,6 +336,15 @@ vips_foreign_save_heif_build( VipsObject *object )
if( vips_copy( save->ready, &heif->image, NULL ) )
return( -1 );
/* Compression defaults to VIPS_FOREIGN_HEIF_COMPRESSION_AV1 for .avif
* suffix.
*/
filename = vips_connection_filename( VIPS_CONNECTION( heif->target ) );
if( !vips_object_argument_isset( object, "compression" ) &&
filename &&
vips_iscasepostfix( filename, ".avif" ) )
heif->compression = VIPS_FOREIGN_HEIF_COMPRESSION_AV1;
error = heif_context_get_encoder_for_format( heif->ctx,
(enum heif_compression_format) heif->compression,
&heif->encoder );
@ -370,7 +380,7 @@ vips_foreign_save_heif_build( VipsObject *object )
chroma = heif->subsample_mode == VIPS_FOREIGN_SUBSAMPLE_OFF ||
( heif->subsample_mode == VIPS_FOREIGN_SUBSAMPLE_AUTO &&
heif->Q > 90 ) ? "444" : "420";
heif->Q >= 90 ) ? "444" : "420";
error = heif_encoder_set_parameter_string( heif->encoder,
"chroma", chroma );
if( error.code &&
@ -566,7 +576,7 @@ vips_foreign_save_heif_file_class_init( VipsForeignSaveHeifFileClass *class )
VIPS_ARG_STRING( class, "filename", 1,
_( "Filename" ),
_( "Filename to load from" ),
_( "Filename to save to" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveHeifFile, filename ),
NULL );
@ -722,12 +732,13 @@ vips_foreign_save_heif_target_init( VipsForeignSaveHeifTarget *target )
*
* Set @lossless %TRUE to switch to lossless compression.
*
* Use @compression to set the encoder e.g. HEVC, AVC, AV1
* Use @compression to set the encoder e.g. HEVC, AVC, AV1. It defaults to AV1
* if the target filename ends with ".avif", otherwise HEVC.
*
* Use @speed to control the CPU effort spent improving compression.
* This is currently only applicable to AV1 encoders, defaults to 5.
*
* Chroma subsampling is normally automatically disabled for Q > 90. You can
* Chroma subsampling is normally automatically disabled for Q >= 90. You can
* force the subsampling mode with @subsample_mode.
*
* See also: vips_image_write_to_file(), vips_heifload().

1233
libvips/foreign/jp2kload.c Normal file

File diff suppressed because it is too large Load Diff

1181
libvips/foreign/jp2ksave.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -557,7 +557,7 @@ vips_foreign_save_jpeg_mime_init( VipsForeignSaveJpegMime *mime )
* If @strip is set, no EXIF data, IPTC data, ICC profile or XMP metadata is
* written into the output file.
*
* Chroma subsampling is normally automatically disabled for Q > 90. You can
* Chroma subsampling is normally automatically disabled for Q >= 90. You can
* force the subsampling mode with @subsample_mode.
*
* If @trellis_quant is set and the version of libjpeg supports it

View File

@ -0,0 +1,15 @@
EXTRA_DIST = \
README-ns \
README.md \
patches \
update.sh \
utils
noinst_LTLIBRARIES = libnsgif.la
libnsgif_la_SOURCES = \
libnsgif.h \
libnsgif.c \
lzw.c \
lzw.h

View File

@ -0,0 +1,36 @@
libnsgif - Decoding GIF files
=============================
The functions provided by this library allow for efficient progressive
GIF decoding. Whilst the initialisation does not ensure that there is
sufficient image data to complete the entire frame, it does ensure
that the information provided is valid. Any subsequent attempts to
decode an initialised GIF are guaranteed to succeed, and any bytes of
the image not present are assumed to be totally transparent.
To begin decoding a GIF, the 'gif' structure must be initialised with
the 'gif_data' and 'buffer_size' set to their initial values. The
'buffer_position' should initially be 0, and will be internally
updated as the decoding commences. The caller should then repeatedly
call gif_initialise() with the structure until the function returns 1,
or no more data is avaliable.
Once the initialisation has begun, the decoder completes the variables
'frame_count' and 'frame_count_partial'. The former being the total
number of frames that have been successfully initialised, and the
latter being the number of frames that a partial amount of data is
available for. This assists the caller in managing the animation
whilst decoding is continuing.
To decode a frame, the caller must use gif_decode_frame() which
updates the current 'frame_image' to reflect the desired frame. The
required 'disposal_method' is also updated to reflect how the frame
should be plotted. The caller must not assume that the current
'frame_image' will be valid between calls if initialisation is still
occuring, and should either always request that the frame is decoded
(no processing will occur if the 'decoded_frame' has not been
invalidated by initialisation) or perform the check itself.
It should be noted that gif_finalise() should always be called, even
if no frames were initialised. Additionally, it is the responsibility
of the caller to free 'gif_data'.

View File

@ -0,0 +1,16 @@
# libnsgif
This is [libnsgif](https://www.netsurf-browser.org/projects/libnsgif/),
but within the libvips build system.
# To update
Run `./update.sh` to update this copy of libnsgif from the upstream repo. It
will also patch libnsgif.c to prevent it modifying the input.
Last updated 28 Feb 2021.
# To do
No attempt made to run tests or build docs. Though the gif loader is tested as
part of the libvips test suite.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,192 @@
/*
* Copyright 2004 Richard Wilson <richard.wilson@netsurf-browser.org>
* Copyright 2008 Sean Fox <dyntryx@gmail.com>
*
* This file is part of NetSurf's libnsgif, http://www.netsurf-browser.org/
* Licenced under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
*/
/**
* \file
* Interface to progressive animated GIF file decoding.
*/
#ifndef _LIBNSGIF_H_
#define _LIBNSGIF_H_
#include <stdbool.h>
#include <inttypes.h>
/* Error return values */
typedef enum {
GIF_WORKING = 1,
GIF_OK = 0,
GIF_INSUFFICIENT_FRAME_DATA = -1,
GIF_FRAME_DATA_ERROR = -2,
GIF_INSUFFICIENT_DATA = -3,
GIF_DATA_ERROR = -4,
GIF_INSUFFICIENT_MEMORY = -5,
GIF_FRAME_NO_DISPLAY = -6,
GIF_END_OF_FRAME = -7
} gif_result;
/** GIF frame data */
typedef struct gif_frame {
/** whether the frame should be displayed/animated */
bool display;
/** delay (in cs) before animating the frame */
unsigned int frame_delay;
/* Internal members are listed below */
/** offset (in bytes) to the GIF frame data */
unsigned int frame_pointer;
/** whether the frame has previously been used */
bool virgin;
/** whether the frame is totally opaque */
bool opaque;
/** whether a forcable screen redraw is required */
bool redraw_required;
/** how the previous frame should be disposed; affects plotting */
unsigned char disposal_method;
/** whether we acknoledge transparency */
bool transparency;
/** the index designating a transparent pixel */
unsigned char transparency_index;
/** x co-ordinate of redraw rectangle */
unsigned int redraw_x;
/** y co-ordinate of redraw rectangle */
unsigned int redraw_y;
/** width of redraw rectangle */
unsigned int redraw_width;
/** height of redraw rectangle */
unsigned int redraw_height;
} gif_frame;
/* API for Bitmap callbacks */
typedef void* (*gif_bitmap_cb_create)(int width, int height);
typedef void (*gif_bitmap_cb_destroy)(void *bitmap);
typedef unsigned char* (*gif_bitmap_cb_get_buffer)(void *bitmap);
typedef void (*gif_bitmap_cb_set_opaque)(void *bitmap, bool opaque);
typedef bool (*gif_bitmap_cb_test_opaque)(void *bitmap);
typedef void (*gif_bitmap_cb_modified)(void *bitmap);
/** Bitmap callbacks function table */
typedef struct gif_bitmap_callback_vt {
/** Create a bitmap. */
gif_bitmap_cb_create bitmap_create;
/** Free a bitmap. */
gif_bitmap_cb_destroy bitmap_destroy;
/** Return a pointer to the pixel data in a bitmap. */
gif_bitmap_cb_get_buffer bitmap_get_buffer;
/* Members below are optional */
/** Sets whether a bitmap should be plotted opaque. */
gif_bitmap_cb_set_opaque bitmap_set_opaque;
/** Tests whether a bitmap has an opaque alpha channel. */
gif_bitmap_cb_test_opaque bitmap_test_opaque;
/** The bitmap image has changed, so flush any persistant cache. */
gif_bitmap_cb_modified bitmap_modified;
} gif_bitmap_callback_vt;
/** GIF animation data */
typedef struct gif_animation {
/** LZW decode context */
void *lzw_ctx;
/** callbacks for bitmap functions */
gif_bitmap_callback_vt bitmap_callbacks;
/** pointer to GIF data */
unsigned char *gif_data;
/** width of GIF (may increase during decoding) */
unsigned int width;
/** heigth of GIF (may increase during decoding) */
unsigned int height;
/** number of frames decoded */
unsigned int frame_count;
/** number of frames partially decoded */
unsigned int frame_count_partial;
/** decoded frames */
gif_frame *frames;
/** current frame decoded to bitmap */
int decoded_frame;
/** currently decoded image; stored as bitmap from bitmap_create callback */
void *frame_image;
/** number of times to loop animation */
int loop_count;
/* Internal members are listed below */
/** current index into GIF data */
unsigned int buffer_position;
/** total number of bytes of GIF data available */
unsigned int buffer_size;
/** current number of frame holders */
unsigned int frame_holders;
/** index in the colour table for the background colour */
unsigned int background_index;
/** image aspect ratio (ignored) */
unsigned int aspect_ratio;
/** size of colour table (in entries) */
unsigned int colour_table_size;
/** whether the GIF has a global colour table */
bool global_colours;
/** global colour table */
unsigned int *global_colour_table;
/** local colour table */
unsigned int *local_colour_table;
/** previous frame for GIF_FRAME_RESTORE */
void *prev_frame;
/** previous frame index */
int prev_index;
/** previous frame width */
unsigned prev_width;
/** previous frame height */
unsigned prev_height;
} gif_animation;
/**
* Initialises necessary gif_animation members.
*/
void gif_create(gif_animation *gif, gif_bitmap_callback_vt *bitmap_callbacks);
/**
* Initialises any workspace held by the animation and attempts to decode
* any information that hasn't already been decoded.
* If an error occurs, all previously decoded frames are retained.
*
* @return Error return value.
* - GIF_FRAME_DATA_ERROR for GIF frame data error
* - GIF_INSUFFICIENT_FRAME_DATA for insufficient data to process
* any more frames
* - GIF_INSUFFICIENT_MEMORY for memory error
* - GIF_DATA_ERROR for GIF error
* - GIF_INSUFFICIENT_DATA for insufficient data to do anything
* - GIF_OK for successful decoding
* - GIF_WORKING for successful decoding if more frames are expected
*/
gif_result gif_initialise(gif_animation *gif, size_t size, unsigned char *data);
/**
* Decodes a GIF frame.
*
* @return Error return value. If a frame does not contain any image data,
* GIF_OK is returned and gif->current_error is set to
* GIF_FRAME_NO_DISPLAY
* - GIF_FRAME_DATA_ERROR for GIF frame data error
* - GIF_INSUFFICIENT_FRAME_DATA for insufficient data to complete the frame
* - GIF_DATA_ERROR for GIF error (invalid frame header)
* - GIF_INSUFFICIENT_DATA for insufficient data to do anything
* - GIF_INSUFFICIENT_MEMORY for insufficient memory to process
* - GIF_OK for successful decoding
*/
gif_result gif_decode_frame(gif_animation *gif, unsigned int frame);
/**
* Releases any workspace held by a gif
*/
void gif_finalise(gif_animation *gif);
#endif

View File

@ -0,0 +1,555 @@
/*
* This file is part of NetSurf's LibNSGIF, http://www.netsurf-browser.org/
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright 2017 Michael Drake <michael.drake@codethink.co.uk>
* Copyright 2021 Michael Drake <tlsa@netsurf-browser.org>
*/
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include "lzw.h"
/**
* \file
* \brief LZW decompression (implementation)
*
* Decoder for GIF LZW data.
*/
/** Maximum number of lzw table entries. */
#define LZW_TABLE_ENTRY_MAX (1u << LZW_CODE_MAX)
/**
* Context for reading LZW data.
*
* LZW data is split over multiple sub-blocks. Each sub-block has a
* byte at the start, which says the sub-block size, and then the data.
* Zero-size sub-blocks have no data, and the biggest sub-block size is
* 255, which means there are 255 bytes of data following the sub-block
* size entry.
*
* Note that an individual LZW code can be split over up to three sub-blocks.
*/
struct lzw_read_ctx {
const uint8_t *restrict data; /**< Pointer to start of input data */
uint32_t data_len; /**< Input data length */
uint32_t data_sb_next; /**< Offset to sub-block size */
const uint8_t *sb_data; /**< Pointer to current sub-block in data */
size_t sb_bit; /**< Current bit offset in sub-block */
uint32_t sb_bit_count; /**< Bit count in sub-block */
};
/**
* LZW table entry.
*
* Records in the table are composed of 1 or more entries.
* Entries refer to the entry they extend which can be followed to compose
* the complete record. To compose the record in reverse order, take
* the `value` from each entry, and move to the entry it extends.
* If the extended entries index is < the current clear_code, then it
* is the last entry in the record.
*/
struct lzw_table_entry {
uint8_t value; /**< Last value for record ending at entry. */
uint8_t first; /**< First value in entry's entire record. */
uint16_t count; /**< Count of values in this entry's record. */
uint16_t extends; /**< Offset in table to previous entry. */
};
/**
* LZW decompression context.
*/
struct lzw_ctx {
struct lzw_read_ctx input; /**< Input reading context */
uint32_t prev_code; /**< Code read from input previously. */
uint32_t prev_code_first; /**< First value of previous code. */
uint32_t prev_code_count; /**< Total values for previous code. */
uint32_t initial_code_size; /**< Starting LZW code size. */
uint32_t code_size; /**< Current LZW code size. */
uint32_t code_max; /**< Max code value for current code size. */
uint32_t clear_code; /**< Special Clear code value */
uint32_t eoi_code; /**< Special End of Information code value */
uint32_t table_size; /**< Next position in table to fill. */
uint32_t output_code; /**< Code that has been partially output. */
uint32_t output_left; /**< Number of values left for output_code. */
uint32_t transparency_idx; /**< Index representing transparency. */
uint32_t *restrict colour_map; /**< Index to pixel colour mapping */
/** Output value stack. */
uint8_t stack_base[LZW_TABLE_ENTRY_MAX];
/** LZW code table. Generated during decode. */
struct lzw_table_entry table[LZW_TABLE_ENTRY_MAX];
};
/* Exported function, documented in lzw.h */
lzw_result lzw_context_create(struct lzw_ctx **ctx)
{
struct lzw_ctx *c = malloc(sizeof(*c));
if (c == NULL) {
return LZW_NO_MEM;
}
*ctx = c;
return LZW_OK;
}
/* Exported function, documented in lzw.h */
void lzw_context_destroy(struct lzw_ctx *ctx)
{
free(ctx);
}
/**
* Advance the context to the next sub-block in the input data.
*
* \param[in] ctx LZW reading context, updated on success.
* \return LZW_OK or LZW_OK_EOD on success, appropriate error otherwise.
*/
static lzw_result lzw__block_advance(struct lzw_read_ctx *restrict ctx)
{
uint32_t block_size;
uint32_t next_block_pos = ctx->data_sb_next;
const uint8_t *data_next = ctx->data + next_block_pos;
if (next_block_pos >= ctx->data_len) {
return LZW_NO_DATA;
}
block_size = *data_next;
if ((next_block_pos + block_size) >= ctx->data_len) {
return LZW_NO_DATA;
}
ctx->sb_bit = 0;
ctx->sb_bit_count = block_size * 8;
if (block_size == 0) {
ctx->data_sb_next += 1;
return LZW_OK_EOD;
}
ctx->sb_data = data_next + 1;
ctx->data_sb_next += block_size + 1;
return LZW_OK;
}
/**
* Get the next LZW code of given size from the raw input data.
*
* Reads codes from the input data stream coping with GIF data sub-blocks.
*
* \param[in] ctx LZW reading context, updated.
* \param[in] code_size Size of LZW code to get from data.
* \param[out] code_out Returns an LZW code on success.
* \return LZW_OK or LZW_OK_EOD on success, appropriate error otherwise.
*/
static inline lzw_result lzw__read_code(
struct lzw_read_ctx *restrict ctx,
uint32_t code_size,
uint32_t *restrict code_out)
{
uint32_t code = 0;
uint32_t current_bit = ctx->sb_bit & 0x7;
if (ctx->sb_bit + 24 <= ctx->sb_bit_count) {
/* Fast path: read three bytes from this sub-block */
const uint8_t *data = ctx->sb_data + (ctx->sb_bit >> 3);
code |= *data++ << 0;
code |= *data++ << 8;
code |= *data << 16;
ctx->sb_bit += code_size;
} else {
/* Slow path: code spans sub-blocks */
uint8_t byte_advance = (current_bit + code_size) >> 3;
uint8_t byte = 0;
uint8_t bits_remaining_0 = (code_size < (8u - current_bit)) ?
code_size : (8u - current_bit);
uint8_t bits_remaining_1 = code_size - bits_remaining_0;
uint8_t bits_used[3] = {
[0] = bits_remaining_0,
[1] = bits_remaining_1 < 8 ? bits_remaining_1 : 8,
[2] = bits_remaining_1 - 8,
};
assert(byte_advance <= 2);
while (true) {
const uint8_t *data = ctx->sb_data;
lzw_result res;
/* Get any data from end of this sub-block */
while (byte <= byte_advance &&
ctx->sb_bit < ctx->sb_bit_count) {
code |= data[ctx->sb_bit >> 3] << (byte << 3);
ctx->sb_bit += bits_used[byte];
byte++;
}
/* Check if we have all we need */
if (byte > byte_advance) {
break;
}
/* Move to next sub-block */
res = lzw__block_advance(ctx);
if (res != LZW_OK) {
return res;
}
}
}
*code_out = (code >> current_bit) & ((1 << code_size) - 1);
return LZW_OK;
}
/**
* Clear LZW code table.
*
* \param[in] ctx LZW reading context, updated.
* \return LZW_OK or error code.
*/
static inline void lzw__clear_table(
struct lzw_ctx *ctx)
{
/* Reset table building context */
ctx->code_size = ctx->initial_code_size;
ctx->code_max = (1 << ctx->initial_code_size) - 1;
ctx->table_size = ctx->eoi_code + 1;
}
/* Exported function, documented in lzw.h */
lzw_result lzw_decode_init(
struct lzw_ctx *ctx,
const uint8_t *compressed_data,
uint32_t compressed_data_len,
uint32_t compressed_data_pos,
uint8_t minimum_code_size)
{
struct lzw_table_entry *table = ctx->table;
if (minimum_code_size >= LZW_CODE_MAX) {
return LZW_BAD_ICODE;
}
/* Initialise the input reading context */
ctx->input.data = compressed_data;
ctx->input.data_len = compressed_data_len;
ctx->input.data_sb_next = compressed_data_pos;
ctx->input.sb_bit = 0;
ctx->input.sb_bit_count = 0;
/* Initialise the table building context */
ctx->initial_code_size = minimum_code_size + 1;
ctx->clear_code = (1 << minimum_code_size) + 0;
ctx->eoi_code = (1 << minimum_code_size) + 1;
ctx->output_left = 0;
/* Initialise the standard table entries */
for (uint32_t i = 0; i < ctx->clear_code; ++i) {
table[i].first = i;
table[i].value = i;
table[i].count = 1;
}
lzw__clear_table(ctx);
ctx->prev_code = ctx->clear_code;
return LZW_OK;
}
/**
* Create new table entry.
*
* \param[in] ctx LZW reading context, updated.
* \param[in] code Last value code for new table entry.
*/
static inline void lzw__table_add_entry(
struct lzw_ctx *ctx,
uint32_t code)
{
struct lzw_table_entry *entry = &ctx->table[ctx->table_size];
entry->value = code;
entry->first = ctx->prev_code_first;
entry->count = ctx->prev_code_count + 1;
entry->extends = ctx->prev_code;
ctx->table_size++;
}
typedef uint32_t (*lzw_writer_fn)(
struct lzw_ctx *ctx,
void *restrict output,
uint32_t length,
uint32_t used,
uint32_t code,
uint32_t left);
/**
* Get the next LZW code and write its value(s) to output buffer.
*
* \param[in] ctx LZW reading context, updated.
* \param[in] output Array to write output values into.
* \param[in] length Size of output array.
* \param[in] write_pixels Function for writing pixels to output.
* \param[in,out] used Number of values written. Updated on exit.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
static inline lzw_result lzw__decode(struct lzw_ctx *ctx,
void *restrict output,
uint32_t length,
lzw_writer_fn write_pixels,
uint32_t *restrict used)
{
lzw_result res;
uint32_t code;
/* Get a new code from the input */
res = lzw__read_code(&ctx->input, ctx->code_size, &code);
if (res != LZW_OK) {
return res;
}
/* Handle the new code */
if (code == ctx->eoi_code) {
/* Got End of Information code */
return LZW_EOI_CODE;
} else if (code > ctx->table_size) {
/* Code is invalid */
return LZW_BAD_CODE;
} else if (code == ctx->clear_code) {
lzw__clear_table(ctx);
} else {
if (ctx->prev_code == ctx->clear_code) {
if (code > ctx->clear_code) {
return LZW_BAD_ICODE;
}
} else if (ctx->table_size < LZW_TABLE_ENTRY_MAX) {
uint32_t size = ctx->table_size;
lzw__table_add_entry(ctx, (code < size) ?
ctx->table[code].first :
ctx->prev_code_first);
/* Ensure code size is increased, if needed. */
if (size == ctx->code_max &&
ctx->code_size < LZW_CODE_MAX) {
ctx->code_size++;
ctx->code_max = (1 << ctx->code_size) - 1;
}
}
*used += write_pixels(ctx, output, length, *used, code,
ctx->table[code].count);
}
/* Store details of this code as "previous code" to the context. */
ctx->prev_code_first = ctx->table[code].first;
ctx->prev_code_count = ctx->table[code].count;
ctx->prev_code = code;
return LZW_OK;
}
/**
* Write values for this code to the output stack.
*
* If there isn't enough space in the output stack, this function will write
* the as many as it can into the output. If `ctx->output_left > 0` after
* this call, then there is more data for this code left to output. The code
* is stored to the context as `ctx->output_code`.
*
* \param[in] ctx LZW reading context, updated.
* \param[in] output Array to write output values into.
* \param[in] length Size of output array.
* \param[in] used Current position in output array.
* \param[in] code LZW code to output values for.
* \param[in] left Number of values remaining to output for this value.
* \return Number of pixel values written.
*/
static inline uint32_t lzw__write_pixels(struct lzw_ctx *ctx,
void *restrict output,
uint32_t length,
uint32_t used,
uint32_t code,
uint32_t left)
{
uint8_t *restrict output_pos = (uint8_t *)output + used;
const struct lzw_table_entry * const table = ctx->table;
uint32_t space = length - used;
uint32_t count = left;
if (count > space) {
left = count - space;
count = space;
} else {
left = 0;
}
ctx->output_code = code;
ctx->output_left = left;
/* Skip over any values we don't have space for. */
for (unsigned i = left; i != 0; i--) {
const struct lzw_table_entry *entry = table + code;
code = entry->extends;
}
output_pos += count;
for (unsigned i = count; i != 0; i--) {
const struct lzw_table_entry *entry = table + code;
*--output_pos = entry->value;
code = entry->extends;
}
return count;
}
/* Exported function, documented in lzw.h */
lzw_result lzw_decode(struct lzw_ctx *ctx,
const uint8_t *restrict* const restrict data,
uint32_t *restrict used)
{
*used = 0;
*data = ctx->stack_base;
return lzw__decode(ctx, ctx->stack_base, sizeof(ctx->stack_base),
lzw__write_pixels, used);
}
/* Exported function, documented in lzw.h */
lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
const uint8_t ** const data,
uint32_t *restrict used)
{
*used = 0;
*data = ctx->stack_base;
if (ctx->output_left != 0) {
*used += lzw__write_pixels(ctx,
ctx->stack_base, sizeof(ctx->stack_base), *used,
ctx->output_code, ctx->output_left);
}
while (*used != sizeof(ctx->stack_base)) {
lzw_result res = lzw__decode(ctx,
ctx->stack_base, sizeof(ctx->stack_base),
lzw__write_pixels, used);
if (res != LZW_OK) {
return res;
}
}
return LZW_OK;
}
/**
* Write colour mapped values for this code to the output stack.
*
* If there isn't enough space in the output stack, this function will write
* the as many as it can into the output. If `ctx->output_left > 0` after
* this call, then there is more data for this code left to output. The code
* is stored to the context as `ctx->output_code`.
*
* \param[in] ctx LZW reading context, updated.
* \param[in] output Array to write output values into.
* \param[in] length Size of output array.
* \param[in] used Current position in output array.
* \param[in] code LZW code to output values for.
* \param[in] left Number of values remaining to output for this value.
* \return Number of pixel values written.
*/
static inline uint32_t lzw__write_pixels_map(struct lzw_ctx *ctx,
void *restrict buffer,
uint32_t length,
uint32_t used,
uint32_t code,
uint32_t left)
{
uint32_t *restrict stack_pos = (uint32_t *)buffer + used;
const struct lzw_table_entry * const table = ctx->table;
uint32_t space = length - used;
uint32_t count = left;
if (count > space) {
left = count - space;
count = space;
} else {
left = 0;
}
ctx->output_code = code;
ctx->output_left = left;
for (unsigned i = left; i != 0; i--) {
const struct lzw_table_entry *entry = table + code;
code = entry->extends;
}
stack_pos += count;
for (unsigned i = count; i != 0; i--) {
const struct lzw_table_entry *entry = table + code;
--stack_pos;
if (entry->value != ctx->transparency_idx) {
*stack_pos = ctx->colour_map[entry->value];
}
code = entry->extends;
}
return count;
}
/* Exported function, documented in lzw.h */
lzw_result lzw_decode_map_continuous(struct lzw_ctx *ctx,
uint32_t transparency_idx,
uint32_t *restrict colour_map,
uint32_t *restrict data,
uint32_t length,
uint32_t *restrict used)
{
*used = 0;
ctx->transparency_idx = transparency_idx;
ctx->colour_map = colour_map;
if (ctx->output_left != 0) {
*used += lzw__write_pixels_map(ctx, data, length, *used,
ctx->output_code, ctx->output_left);
}
while (*used != sizeof(ctx->stack_base)) {
lzw_result res = lzw__decode(ctx, data, length,
lzw__write_pixels_map, used);
if (res != LZW_OK) {
return res;
}
}
return LZW_OK;
}

View File

@ -0,0 +1,134 @@
/*
* This file is part of NetSurf's LibNSGIF, http://www.netsurf-browser.org/
* Licensed under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright 2017 Michael Drake <michael.drake@codethink.co.uk>
*/
#ifndef LZW_H_
#define LZW_H_
/**
* \file
* \brief LZW decompression (interface)
*
* Decoder for GIF LZW data.
*/
/** Maximum LZW code size in bits */
#define LZW_CODE_MAX 12
/* Declare lzw internal context structure */
struct lzw_ctx;
/** LZW decoding response codes */
typedef enum lzw_result {
LZW_OK, /**< Success */
LZW_OK_EOD, /**< Success; reached zero-length sub-block */
LZW_NO_MEM, /**< Error: Out of memory */
LZW_NO_DATA, /**< Error: Out of data */
LZW_EOI_CODE, /**< Error: End of Information code */
LZW_BAD_ICODE, /**< Error: Bad initial LZW code */
LZW_BAD_CODE, /**< Error: Bad LZW code */
} lzw_result;
/**
* Create an LZW decompression context.
*
* \param[out] ctx Returns an LZW decompression context. Caller owned,
* free with lzw_context_destroy().
* \return LZW_OK on success, or appropriate error code otherwise.
*/
lzw_result lzw_context_create(
struct lzw_ctx **ctx);
/**
* Destroy an LZW decompression context.
*
* \param[in] ctx The LZW decompression context to destroy.
*/
void lzw_context_destroy(
struct lzw_ctx *ctx);
/**
* Initialise an LZW decompression context for decoding.
*
* Caller owns neither `stack_base_out` or `stack_pos_out`.
*
* \param[in] ctx The LZW decompression context to initialise.
* \param[in] compressed_data The compressed data.
* \param[in] compressed_data_len Byte length of compressed data.
* \param[in] compressed_data_pos Start position in data. Must be position
* of a size byte at sub-block start.
* \param[in] minimum_code_size The LZW Minimum Code Size.
* \param[out] stack_base_out Returns base of decompressed data stack.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
lzw_result lzw_decode_init(
struct lzw_ctx *ctx,
const uint8_t *compressed_data,
uint32_t compressed_data_len,
uint32_t compressed_data_pos,
uint8_t minimum_code_size);
/**
* Read a single LZW code and write into lzw context owned output buffer.
*
* Ensure anything in output is used before calling this, as anything
* on the there before this call will be trampled.
*
* \param[in] ctx LZW reading context, updated.
* \param[out] data Returns pointer to array of output values.
* \param[out] used Returns the number of values written to data.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
lzw_result lzw_decode(struct lzw_ctx *ctx,
const uint8_t *restrict *const restrict data,
uint32_t *restrict used);
/**
* Read input codes until end of lzw context owned output buffer.
*
* Ensure anything in output is used before calling this, as anything
* on the there before this call will be trampled.
*
* \param[in] ctx LZW reading context, updated.
* \param[out] data Returns pointer to array of output values.
* \param[out] used Returns the number of values written to data.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
lzw_result lzw_decode_continuous(struct lzw_ctx *ctx,
const uint8_t ** const data,
uint32_t *restrict used);
/**
* Read LZW codes into client buffer, mapping output to colours.
*
* Ensure anything in output is used before calling this, as anything
* on the there before this call will be trampled.
*
* For transparency to work correctly, the given client buffer must have
* the values from the previous frame. The transparency_idx should be a value
* of 256 or above, if the frame does not have transparency.
*
* \param[in] ctx LZW reading context, updated.
* \param[in] transparency_idx Index representing transparency.
* \param[in] colour_map Index to pixel colour mapping
* \param[in] data Client buffer to fill with colour mapped values.
* \param[in] length Size of output array.
* \param[out] used Returns the number of values written to data.
* \return LZW_OK on success, or appropriate error code otherwise.
*/
lzw_result lzw_decode_map_continuous(struct lzw_ctx *ctx,
uint32_t transparency_idx,
uint32_t *restrict colour_table,
uint32_t *restrict data,
uint32_t length,
uint32_t *restrict used);
#endif

View File

@ -0,0 +1,32 @@
--- libnsgif-orig.c 2021-02-28 14:10:41.818557190 +0000
+++ libnsgif.c 2021-02-28 14:11:55.942285930 +0000
@@ -435,20 +435,15 @@
block_size = gif_data[0] + 1;
/* Check if the frame data runs off the end of the file */
if ((int)(gif_bytes - block_size) < 0) {
- /* Try to recover by signaling the end of the gif.
- * Once we get garbage data, there is no logical way to
- * determine where the next frame is. It's probably
- * better to partially load the gif than not at all.
- */
- if (gif_bytes >= 2) {
- gif_data[0] = 0;
- gif_data[1] = GIF_TRAILER;
- gif_bytes = 1;
- ++gif_data;
- break;
- } else {
- return GIF_INSUFFICIENT_FRAME_DATA;
- }
+ /* jcupitt 15/9/19
+ *
+ * There was code here to set a TRAILER tag. But this
+ * wrote to the input buffer, which will not work for
+ * libvips, where buffers can be mmaped read only files.
+ *
+ * Instead, just signal insufficient frame data.
+ */
+ return GIF_INSUFFICIENT_FRAME_DATA;
} else {
gif_bytes -= block_size;
gif_data += block_size;

View File

@ -0,0 +1,258 @@
/* under libvips, compile with:
*
* gcc -g -Wall decode_gif.c `pkg-config vips --cflags --libs`
*/
/*
* Copyright 2008 Sean Fox <dyntryx@gmail.com>
* Copyright 2008 James Bursa <james@netsurf-browser.org>
*
* This file is part of NetSurf's libnsgif, http://www.netsurf-browser.org/
* Licenced under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
*/
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <vips/vips.h>
#include "../libnsgif.h"
#define BYTES_PER_PIXEL 4
#define MAX_IMAGE_BYTES (48 * 1024 * 1024)
static void *bitmap_create(int width, int height)
{
/* ensure a stupidly large bitmap is not created */
if (((long long)width * (long long)height) > (MAX_IMAGE_BYTES/BYTES_PER_PIXEL)) {
return NULL;
}
return calloc(width * height, BYTES_PER_PIXEL);
}
static void bitmap_set_opaque(void *bitmap, bool opaque)
{
(void) opaque; /* unused */
(void) bitmap; /* unused */
assert(bitmap);
}
static bool bitmap_test_opaque(void *bitmap)
{
(void) bitmap; /* unused */
assert(bitmap);
return false;
}
static unsigned char *bitmap_get_buffer(void *bitmap)
{
assert(bitmap);
return bitmap;
}
static void bitmap_destroy(void *bitmap)
{
assert(bitmap);
free(bitmap);
}
static void bitmap_modified(void *bitmap)
{
(void) bitmap; /* unused */
assert(bitmap);
return;
}
static unsigned char *load_file(const char *path, size_t *data_size)
{
FILE *fd;
struct stat sb;
unsigned char *buffer;
size_t size;
size_t n;
fd = fopen(path, "rb");
if (!fd) {
perror(path);
exit(EXIT_FAILURE);
}
if (stat(path, &sb)) {
perror(path);
exit(EXIT_FAILURE);
}
size = sb.st_size;
buffer = malloc(size);
if (!buffer) {
fprintf(stderr, "Unable to allocate %lld bytes\n",
(long long) size);
exit(EXIT_FAILURE);
}
n = fread(buffer, 1, size, fd);
if (n != size) {
perror(path);
exit(EXIT_FAILURE);
}
fclose(fd);
*data_size = size;
return buffer;
}
static void warning(const char *context, gif_result code)
{
fprintf(stderr, "%s failed: ", context);
switch (code)
{
case GIF_INSUFFICIENT_FRAME_DATA:
fprintf(stderr, "GIF_INSUFFICIENT_FRAME_DATA");
break;
case GIF_FRAME_DATA_ERROR:
fprintf(stderr, "GIF_FRAME_DATA_ERROR");
break;
case GIF_INSUFFICIENT_DATA:
fprintf(stderr, "GIF_INSUFFICIENT_DATA");
break;
case GIF_DATA_ERROR:
fprintf(stderr, "GIF_DATA_ERROR");
break;
case GIF_INSUFFICIENT_MEMORY:
fprintf(stderr, "GIF_INSUFFICIENT_MEMORY");
break;
default:
fprintf(stderr, "unknown code %i", code);
break;
}
fprintf(stderr, "\n");
}
static void write_ppm(FILE* fh, const char *name, gif_animation *gif,
bool no_write)
{
unsigned int i;
gif_result code;
if (!no_write) {
fprintf(fh, "P3\n");
fprintf(fh, "# %s\n", name);
fprintf(fh, "# width %u \n", gif->width);
fprintf(fh, "# height %u \n", gif->height);
fprintf(fh, "# frame_count %u \n", gif->frame_count);
fprintf(fh, "# frame_count_partial %u \n", gif->frame_count_partial);
fprintf(fh, "# loop_count %u \n", gif->loop_count);
fprintf(fh, "%u %u 256\n", gif->width, gif->height * gif->frame_count);
}
/* decode the frames */
for (i = 0; i != gif->frame_count; i++) {
unsigned int row, col;
unsigned char *image;
code = gif_decode_frame(gif, i);
if (code != GIF_OK)
warning("gif_decode_frame", code);
if (!no_write) {
fprintf(fh, "# frame %u:\n", i);
image = (unsigned char *) gif->frame_image;
for (row = 0; row != gif->height; row++) {
for (col = 0; col != gif->width; col++) {
size_t z = (row * gif->width + col) * 4;
fprintf(fh, "%u %u %u ",
(unsigned char) image[z],
(unsigned char) image[z + 1],
(unsigned char) image[z + 2]);
}
fprintf(fh, "\n");
}
}
}
}
int main(int argc, char *argv[])
{
gif_bitmap_callback_vt bitmap_callbacks = {
bitmap_create,
bitmap_destroy,
bitmap_get_buffer,
bitmap_set_opaque,
bitmap_test_opaque,
bitmap_modified
};
gif_animation gif;
size_t size;
gif_result code;
unsigned char *data;
FILE *outf = stdout;
bool no_write = false;
if (argc < 2) {
fprintf(stderr, "Usage: %s image.gif [out]\n", argv[0]);
fprintf(stderr, "\n");
fprintf(stderr, "If [out] is NOWRITE, the gif will be docoded "
"but not output.\n");
fprintf(stderr, "Otherwise [out] is an output filename.\n");
fprintf(stderr, "When [out] is unset, output is to stdout.\n");
return 1;
}
if (argc > 2) {
if (strcmp(argv[2], "NOWRITE") == 0) {
no_write = true;
} else {
outf = fopen(argv[2], "w+");
if (outf == NULL) {
fprintf(stderr, "Unable to open %s for writing\n", argv[2]);
return 2;
}
}
}
/* create our gif animation */
gif_create(&gif, &bitmap_callbacks);
/* load file into memory */
data = load_file(argv[1], &size);
/* begin decoding */
do {
code = gif_initialise(&gif, size, data);
if (code != GIF_OK && code != GIF_WORKING) {
warning("gif_initialise", code);
gif_finalise(&gif);
free(data);
return 1;
}
} while (code != GIF_OK);
write_ppm(outf, argv[1], &gif, no_write);
if (argc > 2 && !no_write) {
fclose(outf);
}
/* clean up */
gif_finalise(&gif);
free(data);
return 0;
}

View File

@ -0,0 +1,22 @@
#!/bin/bash
# attempt to update our copy of libnsgif from the upstream repo
set -e
git clone git://git.netsurf-browser.org/libnsgif.git
echo copying out source files ...
cp libnsgif/src/libnsgif.c .
cp libnsgif/include/libnsgif.h .
cp libnsgif/src/lzw.[ch] .
cp libnsgif/src/utils/log.h utils
echo applying patches ...
for patch in patches/*.patch; do
patch -p0 <$patch
done
echo cleaning up ...
rm -rf libnsgif

View File

@ -0,0 +1,21 @@
/*
* Copyright 2003 James Bursa <bursa@users.sourceforge.net>
* Copyright 2004 John Tytgat <John.Tytgat@aaug.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
* Licenced under the MIT License,
* http://www.opensource.org/licenses/mit-license.php
*/
#include <stdio.h>
#ifndef _LIBNSGIF_LOG_H_
#define _LIBNSGIF_LOG_H_
#ifdef NDEBUG
# define LOG(x) ((void) 0)
#else
# define LOG(x) do { fprintf(stderr, x), fputc('\n', stderr); } while (0)
#endif /* NDEBUG */
#endif /* _LIBNSGIF_LOG_H_ */

View File

@ -95,7 +95,7 @@ typedef struct _VipsForeignLoadNifti {
typedef VipsForeignLoadClass VipsForeignLoadNiftiClass;
G_DEFINE_TYPE( VipsForeignLoadNifti, vips_foreign_load_nifti,
G_DEFINE_ABSTRACT_TYPE( VipsForeignLoadNifti, vips_foreign_load_nifti,
VIPS_TYPE_FOREIGN_LOAD );
static void

948
libvips/foreign/nsgifload.c Normal file
View File

@ -0,0 +1,948 @@
/* load a GIF with libnsgif
*
* 6/10/18
* - from gifload.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
*/
/*
#define VERBOSE
#define VIPS_DEBUG
*/
#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 <errno.h>
#include <ctype.h>
#include <vips/vips.h>
#include <vips/buf.h>
#include <vips/internal.h>
#include <vips/debug.h>
/* TODO:
*
* - libnsgif does not seem to support comment metadata
*
* - it always loads the entire source file into memory
*
* Notes:
*
* - hard to detect mono images -- local_colour_table in libnsgif is only set
* when we decode a frame, so we can't tell just from init whether any
* frames have colour info
*
* - don't bother detecting alpha -- if we can't detect RGB, alpha won't help
* much
*
*/
#ifdef HAVE_NSGIF
#include <libnsgif/libnsgif.h>
#define VIPS_TYPE_FOREIGN_LOAD_GIF (vips_foreign_load_nsgif_get_type())
#define VIPS_FOREIGN_LOAD_GIF( obj ) \
(G_TYPE_CHECK_INSTANCE_CAST( (obj), \
VIPS_TYPE_FOREIGN_LOAD_GIF, VipsForeignLoadNsgif ))
#define VIPS_FOREIGN_LOAD_GIF_CLASS( klass ) \
(G_TYPE_CHECK_CLASS_CAST( (klass), \
VIPS_TYPE_FOREIGN_LOAD_GIF, VipsForeignLoadNsgifClass))
#define VIPS_IS_FOREIGN_LOAD_GIF( obj ) \
(G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_FOREIGN_LOAD_GIF ))
#define VIPS_IS_FOREIGN_LOAD_GIF_CLASS( klass ) \
(G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_FOREIGN_LOAD_GIF ))
#define VIPS_FOREIGN_LOAD_GIF_GET_CLASS( obj ) \
(G_TYPE_INSTANCE_GET_CLASS( (obj), \
VIPS_TYPE_FOREIGN_LOAD_GIF, VipsForeignLoadNsgifClass ))
typedef struct _VipsForeignLoadNsgif {
VipsForeignLoad parent_object;
/* Load this page (frame number).
*/
int page;
/* Load this many pages.
*/
int n;
/* Load from this source (set by subclasses).
*/
VipsSource *source;
/* The animation created by libnsgif.
*/
gif_animation *anim;
/* The data/size pair we pass to libnsgif.
*/
unsigned char *data;
size_t size;
/* The frame_count, after we have removed undisplayable frames.
*/
int frame_count_displayable;
/* Delays between frames (in milliseconds). Array of length
* @frame_count_displayable.
*/
int *delay;
/* A single centisecond value for compatibility.
*/
int gif_delay;
} VipsForeignLoadNsgif;
typedef VipsForeignLoadClass VipsForeignLoadNsgifClass;
G_DEFINE_ABSTRACT_TYPE( VipsForeignLoadNsgif, vips_foreign_load_nsgif,
VIPS_TYPE_FOREIGN_LOAD );
static const char *
vips_foreign_load_nsgif_errstr( gif_result result )
{
switch( result ) {
case GIF_WORKING:
return( _( "Working" ) );
case GIF_OK:
return( _( "OK" ) );
case GIF_INSUFFICIENT_FRAME_DATA:
return( _( "Insufficient data to complete frame" ) );
case GIF_FRAME_DATA_ERROR:
return( _( "GIF frame data error" ) );
case GIF_INSUFFICIENT_DATA:
return( _( "Insufficient data to do anything" ) );
case GIF_DATA_ERROR:
return( _( "GIF header data error" ) );
case GIF_INSUFFICIENT_MEMORY:
return( _( "Insuficient memory to process" ) );
case GIF_FRAME_NO_DISPLAY:
return( _( "No display" ) );
case GIF_END_OF_FRAME:
return( _( "At end of frame" ) );
default:
return( _( "Unknown error" ) );
}
}
static void
vips_foreign_load_nsgif_error( VipsForeignLoadNsgif *gif, gif_result result )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( gif );
vips_error( class->nickname, "%s",
vips_foreign_load_nsgif_errstr( result ) );
}
static void
vips_foreign_load_nsgif_dispose( GObject *gobject )
{
VipsForeignLoadNsgif *gif = (VipsForeignLoadNsgif *) gobject;
VIPS_DEBUG_MSG( "vips_foreign_load_nsgif_dispose:\n" );
if( gif->anim ) {
gif_finalise( gif->anim );
VIPS_FREE( gif->anim );
}
VIPS_UNREF( gif->source );
VIPS_FREE( gif->delay );
G_OBJECT_CLASS( vips_foreign_load_nsgif_parent_class )->
dispose( gobject );
}
static VipsForeignFlags
vips_foreign_load_nsgif_get_flags_filename( const char *filename )
{
return( VIPS_FOREIGN_SEQUENTIAL );
}
static VipsForeignFlags
vips_foreign_load_nsgif_get_flags( VipsForeignLoad *load )
{
return( VIPS_FOREIGN_SEQUENTIAL );
}
static gboolean
vips_foreign_load_nsgif_is_a_source( VipsSource *source )
{
const unsigned char *data;
if( (data = vips_source_sniff( source, 4 )) &&
data[0] == 'G' &&
data[1] == 'I' &&
data[2] == 'F' &&
data[3] == '8' )
return( TRUE );
return( FALSE );
}
#ifdef VERBOSE
static void
print_frame( gif_frame *frame )
{
printf( "frame:\n" );
printf( " display = %d\n", frame->display );
printf( " frame_delay = %d\n", frame->frame_delay );
printf( " virgin = %d\n", frame->virgin );
printf( " opaque = %d\n", frame->opaque );
printf( " redraw_required = %d\n", frame->redraw_required );
printf( " disposal_method = %d\n", frame->disposal_method );
printf( " transparency = %d\n", frame->transparency );
printf( " transparency_index = %d\n", frame->transparency_index );
printf( " redraw_x = %d\n", frame->redraw_x );
printf( " redraw_y = %d\n", frame->redraw_y );
printf( " redraw_width = %d\n", frame->redraw_width );
printf( " redraw_height = %d\n", frame->redraw_height );
}
static void
print_animation( gif_animation *anim )
{
int i;
printf( "animation:\n" );
printf( " width = %d\n", anim->width );
printf( " height = %d\n", anim->height );
printf( " frame_count = %d\n", anim->frame_count );
printf( " frame_count_partial = %d\n", anim->frame_count_partial );
printf( " decoded_frame = %d\n", anim->decoded_frame );
printf( " frame_image = %p\n", anim->frame_image );
printf( " loop_count = %d\n", anim->loop_count );
printf( " frame_holders = %d\n", anim->frame_holders );
printf( " background_index = %d\n", anim->background_index );
printf( " colour_table_size = %d\n", anim->colour_table_size );
printf( " global_colours = %d\n", anim->global_colours );
printf( " global_colour_table = %p\n", anim->global_colour_table );
printf( " local_colour_table = %p\n", anim->local_colour_table );
for( i = 0; i < anim->frame_holders; i++ ) {
printf( "%d ", i );
print_frame( &anim->frames[i] );
}
}
#endif /*VERBOSE*/
static int
vips_foreign_load_nsgif_set_header( VipsForeignLoadNsgif *gif,
VipsImage *image )
{
VIPS_DEBUG_MSG( "vips_foreign_load_nsgif_set_header:\n" );
vips_image_init_fields( image,
gif->anim->width, gif->anim->height * gif->n, 4,
VIPS_FORMAT_UCHAR, VIPS_CODING_NONE,
VIPS_INTERPRETATION_sRGB, 1.0, 1.0 );
vips_image_pipelinev( image, VIPS_DEMAND_STYLE_FATSTRIP, NULL );
if( vips_object_argument_isset( VIPS_OBJECT( gif ), "n" ) )
vips_image_set_int( image,
VIPS_META_PAGE_HEIGHT, gif->anim->height );
vips_image_set_int( image, VIPS_META_N_PAGES,
gif->frame_count_displayable );
vips_image_set_int( image, "loop", gif->anim->loop_count );
vips_image_set_array_int( image, "delay",
gif->delay, gif->frame_count_displayable );
if( gif->anim->global_colours &&
gif->anim->global_colour_table &&
gif->anim->background_index >= 0 &&
gif->anim->background_index < gif->anim->colour_table_size ) {
int index = gif->anim->background_index;
unsigned char *entry = (unsigned char *)
&gif->anim->global_colour_table[index];
double array[3];
array[0] = entry[0];
array[1] = entry[1];
array[2] = entry[2];
vips_image_set_array_double( image, "background", array, 3 );
}
VIPS_SETSTR( image->filename,
vips_connection_filename( VIPS_CONNECTION( gif->source ) ) );
/* DEPRECATED "gif-loop"
*
* Not the correct behavior as loop=1 became gif-loop=0
* but we want to keep the old behavior untouched!
*/
vips_image_set_int( image,
"gif-loop", gif->anim->loop_count == 0 ?
0 : gif->anim->loop_count - 1 );
/* The deprecated gif-delay field is in centiseconds.
*/
vips_image_set_int( image, "gif-delay", gif->gif_delay );
return( 0 );
}
/* Scan the GIF as quickly as we can and extract transparency, bands, pages,
* etc.
*
* Don't flag any errors unless we have to: we want to work for corrupt or
* malformed GIFs.
*
* Close as soon as we can to free up the fd.
*/
static int
vips_foreign_load_nsgif_header( VipsForeignLoad *load )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( load );
VipsForeignLoadNsgif *gif = (VipsForeignLoadNsgif *) load;
const void *data;
size_t size;
gif_result result;
int i;
VIPS_DEBUG_MSG( "vips_foreign_load_nsgif_header:\n" );
/* We map in the image, then minimise to close any underlying file
* object. This won't unmap.
*/
if( !(data = vips_source_map( gif->source, &size )) )
return( -1 );
vips_source_minimise( gif->source );
result = gif_initialise( gif->anim, size, (void *) data );
VIPS_DEBUG_MSG( "gif_initialise() = %d\n", result );
#ifdef VERBOSE
print_animation( gif->anim );
#endif /*VERBOSE*/
if( result != GIF_OK &&
result != GIF_WORKING &&
result != GIF_INSUFFICIENT_FRAME_DATA ) {
vips_foreign_load_nsgif_error( gif, result );
return( -1 );
}
else if( result == GIF_INSUFFICIENT_FRAME_DATA &&
load->fail ) {
vips_error( class->nickname, "%s", _( "truncated GIF" ) );
return( -1 );
}
/* Many GIFs have dead frames at the end. Remove these from our count.
*/
for( i = gif->anim->frame_count - 1;
i >= 0 && !gif->anim->frames[i].display; i-- )
;
gif->frame_count_displayable = i + 1;
#ifdef VERBOSE
if( gif->frame_count_displayable != gif->anim->frame_count )
printf( "vips_foreign_load_nsgif_open: "
"removed %d undisplayable frames\n",
gif->anim->frame_count - gif->frame_count_displayable );
#endif /*VERBOSE*/
if( !gif->frame_count_displayable ) {
vips_error( class->nickname, "%s", _( "no frames in GIF" ) );
return( -1 );
}
if( gif->n == -1 )
gif->n = gif->frame_count_displayable - gif->page;
if( gif->page < 0 ||
gif->n <= 0 ||
gif->page + gif->n > gif->frame_count_displayable ) {
vips_error( class->nickname, "%s", _( "bad page number" ) );
return( -1 );
}
/* In ms, frame_delay in cs.
*/
VIPS_FREE( gif->delay );
if( !(gif->delay = VIPS_ARRAY( NULL,
gif->frame_count_displayable, int )) )
return( -1 );
for( i = 0; i < gif->frame_count_displayable; i++ )
gif->delay[i] = 10 * gif->anim->frames[i].frame_delay;
gif->gif_delay = gif->anim->frames[0].frame_delay;
vips_foreign_load_nsgif_set_header( gif, load->out );
return( 0 );
}
static int
vips_foreign_load_nsgif_generate( VipsRegion *or,
void *seq, void *a, void *b, gboolean *stop )
{
VipsRect *r = &or->valid;
VipsForeignLoadNsgif *gif = (VipsForeignLoadNsgif *) a;
int y;
#ifdef VERBOSE
VIPS_DEBUG_MSG( "vips_foreign_load_nsgif_generate: "
"top = %d, height = %d\n", r->top, r->height );
#endif /*VERBOSE*/
for( y = 0; y < r->height; y++ ) {
/* The page for this output line, and the line number in page.
*/
int page = (r->top + y) / gif->anim->height + gif->page;
int line = (r->top + y) % gif->anim->height;
gif_result result;
VipsPel *p, *q;
g_assert( line >= 0 && line < gif->anim->height );
g_assert( page >= 0 && page < gif->frame_count_displayable );
if( gif->anim->decoded_frame != page ) {
result = gif_decode_frame( gif->anim, page );
VIPS_DEBUG_MSG( " gif_decode_frame(%d) = %d\n",
page, result );
if( result != GIF_OK ) {
vips_foreign_load_nsgif_error( gif, result );
return( -1 );
}
#ifdef VERBOSE
print_animation( gif->anim );
#endif /*VERBOSE*/
}
p = gif->anim->frame_image +
line * gif->anim->width * sizeof( int );
q = VIPS_REGION_ADDR( or, 0, r->top + y );
memcpy( q, p, VIPS_REGION_SIZEOF_LINE( or ) );
}
return( 0 );
}
static int
vips_foreign_load_nsgif_load( VipsForeignLoad *load )
{
VipsForeignLoadNsgif *gif = (VipsForeignLoadNsgif *) load;
VipsImage **t = (VipsImage **)
vips_object_local_array( VIPS_OBJECT( load ), 4 );
VIPS_DEBUG_MSG( "vips_foreign_load_nsgif_load:\n" );
/* Make the output pipeline.
*/
t[0] = vips_image_new();
if( vips_foreign_load_nsgif_set_header( gif, t[0] ) )
return( -1 );
/* Strips 8 pixels high to avoid too many tiny regions.
*/
if( vips_image_generate( t[0],
NULL, vips_foreign_load_nsgif_generate, NULL, gif, NULL ) ||
vips_sequential( t[0], &t[1],
"tile_height", VIPS__FATSTRIP_HEIGHT,
NULL ) ||
vips_image_write( t[1], load->real ) )
return( -1 );
return( 0 );
}
static void
vips_foreign_load_nsgif_class_init( VipsForeignLoadNsgifClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->dispose = vips_foreign_load_nsgif_dispose;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "gifload_base";
object_class->description = _( "load GIF with libnsgif" );
/* High priority, so that we handle vipsheader etc.
*/
foreign_class->priority = 50;
load_class->get_flags_filename =
vips_foreign_load_nsgif_get_flags_filename;
load_class->get_flags = vips_foreign_load_nsgif_get_flags;
load_class->header = vips_foreign_load_nsgif_header;
load_class->load = vips_foreign_load_nsgif_load;
VIPS_ARG_INT( class, "page", 10,
_( "Page" ),
_( "Load this page from the file" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadNsgif, page ),
0, 100000, 0 );
VIPS_ARG_INT( class, "n", 6,
_( "n" ),
_( "Load this many pages" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadNsgif, n ),
-1, 100000, 1 );
}
static void *
vips_foreign_load_nsgif_bitmap_create( int width, int height )
{
/* Enforce max GIF dimensions of 16383 (0x7FFF). This should be enough
* for anyone, and will prevent the worst GIF bombs.
*/
if( width <= 0 ||
width > 16383 ||
height <= 0 ||
height > 16383 ) {
vips_error( "gifload",
"%s", _( "bad image dimensions") );
return( NULL );
}
return g_malloc0( (gsize) width * height * 4 );
}
static void
vips_foreign_load_nsgif_bitmap_set_opaque( void *bitmap, bool opaque )
{
(void) opaque; /* unused */
(void) bitmap; /* unused */
g_assert( bitmap );
}
static bool
vips_foreign_load_nsgif_bitmap_test_opaque( void *bitmap )
{
(void) bitmap; /* unused */
g_assert( bitmap );
return( false );
}
static unsigned char *
vips_foreign_load_nsgif_bitmap_get_buffer( void *bitmap )
{
g_assert( bitmap );
return( bitmap );
}
static void
vips_foreign_load_nsgif_bitmap_destroy( void *bitmap )
{
g_assert( bitmap );
g_free( bitmap );
}
static void
vips_foreign_load_nsgif_bitmap_modified( void *bitmap )
{
(void) bitmap; /* unused */
g_assert( bitmap );
return;
}
static gif_bitmap_callback_vt vips_foreign_load_nsgif_bitmap_callbacks = {
vips_foreign_load_nsgif_bitmap_create,
vips_foreign_load_nsgif_bitmap_destroy,
vips_foreign_load_nsgif_bitmap_get_buffer,
vips_foreign_load_nsgif_bitmap_set_opaque,
vips_foreign_load_nsgif_bitmap_test_opaque,
vips_foreign_load_nsgif_bitmap_modified
};
static void
vips_foreign_load_nsgif_init( VipsForeignLoadNsgif *gif )
{
gif->anim = g_new0( gif_animation, 1 );
gif_create( gif->anim, &vips_foreign_load_nsgif_bitmap_callbacks );
gif->n = 1;
}
typedef struct _VipsForeignLoadNsgifFile {
VipsForeignLoadNsgif parent_object;
/* Filename for load.
*/
char *filename;
} VipsForeignLoadNsgifFile;
typedef VipsForeignLoadNsgifClass VipsForeignLoadNsgifFileClass;
G_DEFINE_TYPE( VipsForeignLoadNsgifFile, vips_foreign_load_nsgif_file,
vips_foreign_load_nsgif_get_type() );
static int
vips_foreign_load_gif_file_build( VipsObject *object )
{
VipsForeignLoadNsgif *gif = (VipsForeignLoadNsgif *) object;
VipsForeignLoadNsgifFile *file = (VipsForeignLoadNsgifFile *) object;
if( file->filename )
if( !(gif->source =
vips_source_new_from_file( file->filename )) )
return( -1 );
if( VIPS_OBJECT_CLASS( vips_foreign_load_nsgif_file_parent_class )->
build( object ) )
return( -1 );
return( 0 );
}
static const char *vips_foreign_nsgif_suffs[] = {
".gif",
NULL
};
static gboolean
vips_foreign_load_nsgif_file_is_a( const char *filename )
{
VipsSource *source;
gboolean result;
if( !(source = vips_source_new_from_file( filename )) )
return( FALSE );
result = vips_foreign_load_nsgif_is_a_source( source );
VIPS_UNREF( source );
return( result );
}
static void
vips_foreign_load_nsgif_file_class_init(
VipsForeignLoadNsgifFileClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignClass *foreign_class = (VipsForeignClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "gifload";
object_class->description = _( "load GIF with libnsgif" );
object_class->build = vips_foreign_load_gif_file_build;
foreign_class->suffs = vips_foreign_nsgif_suffs;
load_class->is_a = vips_foreign_load_nsgif_file_is_a;
VIPS_ARG_STRING( class, "filename", 1,
_( "Filename" ),
_( "Filename to load from" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadNsgifFile, filename ),
NULL );
}
static void
vips_foreign_load_nsgif_file_init( VipsForeignLoadNsgifFile *file )
{
}
typedef struct _VipsForeignLoadNsgifBuffer {
VipsForeignLoadNsgif parent_object;
/* Load from a buffer.
*/
VipsArea *blob;
} VipsForeignLoadNsgifBuffer;
typedef VipsForeignLoadNsgifClass VipsForeignLoadNsgifBufferClass;
G_DEFINE_TYPE( VipsForeignLoadNsgifBuffer, vips_foreign_load_nsgif_buffer,
vips_foreign_load_nsgif_get_type() );
static int
vips_foreign_load_nsgif_buffer_build( VipsObject *object )
{
VipsForeignLoadNsgif *gif = (VipsForeignLoadNsgif *) object;
VipsForeignLoadNsgifBuffer *buffer =
(VipsForeignLoadNsgifBuffer *) object;
if( buffer->blob &&
!(gif->source = vips_source_new_from_memory(
buffer->blob->data,
buffer->blob->length )) )
return( -1 );
if( VIPS_OBJECT_CLASS( vips_foreign_load_nsgif_buffer_parent_class )->
build( object ) )
return( -1 );
return( 0 );
}
static gboolean
vips_foreign_load_nsgif_buffer_is_a_buffer( const void *buf, size_t len )
{
VipsSource *source;
gboolean result;
if( !(source = vips_source_new_from_memory( buf, len )) )
return( FALSE );
result = vips_foreign_load_nsgif_is_a_source( source );
VIPS_UNREF( source );
return( result );
}
static void
vips_foreign_load_nsgif_buffer_class_init(
VipsForeignLoadNsgifBufferClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "gifload_buffer";
object_class->description = _( "load GIF with libnsgif" );
object_class->build = vips_foreign_load_nsgif_buffer_build;
load_class->is_a_buffer = vips_foreign_load_nsgif_buffer_is_a_buffer;
VIPS_ARG_BOXED( class, "buffer", 1,
_( "Buffer" ),
_( "Buffer to load from" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadNsgifBuffer, blob ),
VIPS_TYPE_BLOB );
}
static void
vips_foreign_load_nsgif_buffer_init( VipsForeignLoadNsgifBuffer *buffer )
{
}
typedef struct _VipsForeignLoadNsgifSource {
VipsForeignLoadNsgif parent_object;
/* Load from a source.
*/
VipsSource *source;
} VipsForeignLoadNsgifSource;
typedef VipsForeignLoadClass VipsForeignLoadNsgifSourceClass;
G_DEFINE_TYPE( VipsForeignLoadNsgifSource, vips_foreign_load_nsgif_source,
vips_foreign_load_nsgif_get_type() );
static int
vips_foreign_load_nsgif_source_build( VipsObject *object )
{
VipsForeignLoadNsgif *gif = (VipsForeignLoadNsgif *) object;
VipsForeignLoadNsgifSource *source =
(VipsForeignLoadNsgifSource *) object;
if( source->source ) {
gif->source = source->source;
g_object_ref( gif->source );
}
if( VIPS_OBJECT_CLASS( vips_foreign_load_nsgif_source_parent_class )->
build( object ) )
return( -1 );
return( 0 );
}
static void
vips_foreign_load_nsgif_source_class_init(
VipsForeignLoadNsgifSourceClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsForeignLoadClass *load_class = (VipsForeignLoadClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "gifload_source";
object_class->description = _( "load gif from source" );
object_class->build = vips_foreign_load_nsgif_source_build;
load_class->is_a_source = vips_foreign_load_nsgif_is_a_source;
VIPS_ARG_OBJECT( class, "source", 1,
_( "Source" ),
_( "Source to load from" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsForeignLoadNsgifSource, source ),
VIPS_TYPE_SOURCE );
}
static void
vips_foreign_load_nsgif_source_init( VipsForeignLoadNsgifSource *source )
{
}
#endif /*HAVE_NSGIF*/
/**
* vips_gifload:
* @filename: file to load
* @out: (out): output image
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* * @page: %gint, page (frame) to read
* * @n: %gint, load this many pages
*
* Read a GIF file into a libvips image.
*
* Use @page to select a page to render, numbering from zero.
*
* Use @n to select the number of pages to render. The default is 1. Pages are
* rendered in a vertical column. Set to -1 to mean "until the end of the
* document". Use vips_grid() to change page layout.
*
* The output image is always RGBA.
*
* See also: vips_image_new_from_file().
*
* Returns: 0 on success, -1 on error.
*/
int
vips_gifload( const char *filename, VipsImage **out, ... )
{
va_list ap;
int result;
va_start( ap, out );
result = vips_call_split( "gifload", ap, filename, out );
va_end( ap );
return( result );
}
/**
* vips_gifload_buffer:
* @buf: (array length=len) (element-type guint8): memory area to load
* @len: (type gsize): size of memory area
* @out: (out): image to write
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* * @page: %gint, page (frame) to read
* * @n: %gint, load this many pages
*
* Read a GIF-formatted memory block into a VIPS image. Exactly as
* vips_gifload(), but read from a memory buffer.
*
* You must not free the buffer while @out is active. The
* #VipsObject::postclose signal on @out is a good place to free.
*
* See also: vips_gifload().
*
* Returns: 0 on success, -1 on error.
*/
int
vips_gifload_buffer( void *buf, size_t len, VipsImage **out, ... )
{
va_list ap;
VipsBlob *blob;
int result;
/* We don't take a copy of the data or free it.
*/
blob = vips_blob_new( NULL, buf, len );
va_start( ap, out );
result = vips_call_split( "gifload_buffer", ap, blob, out );
va_end( ap );
vips_area_unref( VIPS_AREA( blob ) );
return( result );
}
/**
* vips_gifload_source:
* @source: source to load
* @out: (out): image to write
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* * @page: %gint, page (frame) to read
* * @n: %gint, load this many pages
*
* Exactly as vips_gifload(), but read from a source.
*
* See also: vips_gifload().
*
* Returns: 0 on success, -1 on error.
*/
int
vips_gifload_source( VipsSource *source, VipsImage **out, ... )
{
va_list ap;
int result;
va_start( ap, out );
result = vips_call_split( "gifload_source", ap, source, out );
va_end( ap );
return( result );
}

View File

@ -226,7 +226,11 @@ read_header( Read *read, VipsImage *out )
VIPS_FORMAT_FLOAT,
VIPS_CODING_NONE, VIPS_INTERPRETATION_scRGB, 1.0, 1.0 );
if( read->tiles )
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_SMALLTILE, NULL );
/* Even though this is a tiled reader, we hint thinstrip
* since with the cache we are quite happy serving that if
* anything downstream would like it.
*/
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
else
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_FATSTRIP, NULL );
}
@ -363,7 +367,8 @@ vips__openexr_read( const char *filename, VipsImage *out )
VipsImage *raw;
VipsImage *t;
/* Tile cache: keep enough for two complete rows of tiles.
/* Tile cache: keep enough for two complete rows of tiles,
* plus 50%.
*/
raw = vips_image_new();
vips_object_local( out, raw );
@ -375,14 +380,11 @@ vips__openexr_read( const char *filename, VipsImage *out )
read, NULL ) )
return( -1 );
/* Copy to out, adding a cache. Enough tiles for a complete
* row, plus 50%.
*/
if( vips_tilecache( raw, &t,
"tile_width", read->tile_width,
"tile_height", read->tile_height,
"max_tiles", (int)
(1.5 * (1 + raw->Xsize / read->tile_width)),
(2.5 * (1 + raw->Xsize / read->tile_width)),
NULL ) )
return( -1 );
if( vips_image_write( t, out ) ) {

View File

@ -245,6 +245,8 @@ void vips__heif_error( struct heif_error *error );
struct heif_image;
void vips__heif_image_print( struct heif_image *img );
extern const char *vips__jp2k_suffs[];
#ifdef __cplusplus
}
#endif /*__cplusplus*/

View File

@ -104,7 +104,7 @@ vips__tiff_openout( const char *path, gboolean bigtiff )
/* Need the utf-16 version on Windows.
*/
#ifdef OS_WIN32
#ifdef G_OS_WIN32
{
GError *error = NULL;
wchar_t *path16;
@ -119,9 +119,9 @@ vips__tiff_openout( const char *path, gboolean bigtiff )
g_free( path16 );
}
#else /*!OS_WIN32*/
#else /*!G_OS_WIN32*/
tif = TIFFOpen( path, mode );
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
if( !tif ) {
vips_error( "tiff",

View File

@ -115,7 +115,7 @@ G_DEFINE_ABSTRACT_TYPE( VipsForeignSaveTiff, vips_foreign_save_tiff,
#define UC VIPS_FORMAT_UCHAR
/* Type promotion for save ... just always go to uchar.
/* Type promotion for jpeg-in-tiff save ... just always go to uchar.
*/
static int bandfmt_jpeg[10] = {
/* UC C US S UI I F X D DX */

View File

@ -328,11 +328,18 @@ write_webp_anim( VipsWebPWrite *write, VipsImage *image, int page_height )
/* There might just be the old gif-delay field. This is centiseconds.
*/
gif_delay = 4;
gif_delay = 10;
if( vips_image_get_typeof( image, "gif-delay" ) &&
vips_image_get_int( image, "gif-delay", &gif_delay ) )
return( -1 );
/* Force frames with a small or no duration to 100ms
* to be consistent with web browsers and other
* transcoding tools.
*/
if( gif_delay <= 1 )
gif_delay = 10;
/* New images have an array of ints instead.
*/
delay = NULL;
@ -371,7 +378,8 @@ write_webp_anim( VipsWebPWrite *write, VipsImage *image, int page_height )
page_index = top / page_height;
if( delay &&
page_index < delay_length )
timestamp_ms += delay[page_index];
timestamp_ms += delay[page_index] <= 10 ?
100 : delay[page_index];
else
timestamp_ms += gif_delay * 10;
}

View File

@ -33,7 +33,6 @@ pkginclude_HEADERS = \
mosaicing.h \
create.h \
video.h \
cimg_funcs.h \
object.h \
private.h \
rect.h \

View File

@ -1,51 +0,0 @@
/* cimg_funcs.h
*
* 20/9/09
* - from proto.h
*/
/*
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 IM_CIMG_FUNCS_H
#define IM_CIMG_FUNCS_H
#ifdef __cplusplus
extern "C" {
#endif /*__cplusplus*/
#include <vips/vips.h>
int vips_gmic( VipsImage **in, VipsImage **out, int n,
int padding, double x_scale, double y_scale, const char *command, ... )
__attribute__((sentinel));
#ifdef __cplusplus
}
#endif /*__cplusplus*/
#endif /*IM_CIMG_FUNCS_H*/

View File

@ -372,7 +372,7 @@ int vips_openslideload_source( VipsSource *source, VipsImage **out, ... )
/**
* VipsForeignSubsample:
* @VIPS_FOREIGN_SUBSAMPLE_AUTO: prevent subsampling when quality > 90
* @VIPS_FOREIGN_SUBSAMPLE_AUTO: prevent subsampling when quality >= 90
* @VIPS_FOREIGN_SUBSAMPLE_ON: always perform subsampling
* @VIPS_FOREIGN_SUBSAMPLE_OFF: never perform subsampling
*
@ -676,6 +676,19 @@ int vips_niftiload_source( VipsSource *source, VipsImage **out, ... )
int vips_niftisave( VipsImage *in, const char *filename, ... )
__attribute__((sentinel));
int vips_jp2kload( const char *filename, VipsImage **out, ... )
__attribute__((sentinel));
int vips_jp2kload_buffer( void *buf, size_t len, VipsImage **out, ... )
__attribute__((sentinel));
int vips_jp2kload_source( VipsSource *source, VipsImage **out, ... )
__attribute__((sentinel));
int vips_jp2ksave( VipsImage *in, const char *filename, ... )
__attribute__((sentinel));
int vips_jp2ksave_buffer( VipsImage *in, void **buf, size_t *len, ... )
__attribute__((sentinel));
int vips_jp2ksave_target( VipsImage *in, VipsTarget *target, ... )
__attribute__((sentinel));
/**
* VipsForeignDzLayout:
* @VIPS_FOREIGN_DZ_LAYOUT_DZ: use DeepZoom directory layout

View File

@ -365,7 +365,6 @@ int vips_object_get_argument_priority( VipsObject *object, const char *name );
VIPS_ARGUMENT_COLLECT_END
*/
#if GLIB_CHECK_VERSION( 2, 24, 0 )
#define VIPS_ARGUMENT_COLLECT_SET( PSPEC, ARG_CLASS, AP ) \
if( (ARG_CLASS->flags & VIPS_ARGUMENT_INPUT) ) { \
GValue value = { 0, }; \
@ -383,25 +382,6 @@ int vips_object_get_argument_priority( VipsObject *object, const char *name );
VIPS_DEBUG_MSG( "VIPS_OBJECT_COLLECT_SET: err\n" ); \
g_free( error ); \
}
#else
#define VIPS_ARGUMENT_COLLECT_SET( PSPEC, ARG_CLASS, AP ) \
if( (ARG_CLASS->flags & VIPS_ARGUMENT_INPUT) ) { \
GValue value = { 0, }; \
gchar *error = NULL; \
\
/* Input args are given inline, eg. ("factor", 12.0) \
* and must be collected. \
*/ \
g_value_init( &value, G_PARAM_SPEC_VALUE_TYPE( PSPEC ) ); \
G_VALUE_COLLECT( &value, AP, 0, &error ); \
\
/* Don't bother with the error message. \
*/ \
if( error ) { \
VIPS_DEBUG_MSG( "VIPS_OBJECT_COLLECT_SET: err\n" ); \
g_free( error ); \
}
#endif
#define VIPS_ARGUMENT_COLLECT_GET( PSPEC, ARG_CLASS, AP ) \
g_value_unset( &value ); \

View File

@ -92,7 +92,7 @@ G_STMT_START { \
(void) g_once( ONCE, FUNC, CLIENT ); \
} G_STMT_END
/* VIPS_RINT() does "bankers rounding", it rounds to the nerarest even integer.
/* VIPS_RINT() does "bankers rounding", it rounds to the nearest even integer.
* For things like image geometry, we want strict nearest int.
*
* If you know it's unsigned, _UINT is a little faster.

View File

@ -153,7 +153,6 @@ extern "C" {
#include <vips/draw.h>
#include <vips/create.h>
#include <vips/video.h>
#include <vips/cimg_funcs.h>
/* We can't use _ here since this will be compiled by our clients and they may
* not have _().

View File

@ -65,10 +65,10 @@
#include <vips/thread.h>
#include <vips/debug.h>
#ifdef OS_WIN32
#ifdef G_OS_WIN32
#include <windows.h>
#include <lmerr.h>
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
/**
* SECTION: errors
@ -294,7 +294,7 @@ vips_verror_system( int err, const char *domain, const char *fmt, va_list ap )
{
vips_verror( domain, fmt, ap );
#ifdef OS_WIN32
#ifdef G_OS_WIN32
{
char *buf;
@ -310,7 +310,7 @@ vips_verror_system( int err, const char *domain, const char *fmt, va_list ap )
LocalFree( buf );
}
}
#else /*OS_WIN32*/
#else /*!G_OS_WIN32*/
{
char *buf;
@ -318,7 +318,7 @@ vips_verror_system( int err, const char *domain, const char *fmt, va_list ap )
vips_error( _( "unix error" ), "%s", buf );
g_free( buf );
}
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
}
/**

View File

@ -801,12 +801,11 @@ static void
vips_image_add_progress( VipsImage *image )
{
if( vips__progress ||
g_getenv( "VIPS_PROGRESS" )
#if ENABLE_DEPRECATED
g_getenv( "VIPS_PROGRESS" ) ||
g_getenv( "IM_PROGRESS" ) ) {
#else
g_getenv( "VIPS_PROGRESS" ) ) {
|| g_getenv( "IM_PROGRESS" )
#endif
) {
/* Keep the %complete we displayed last time here.
*/
@ -1676,14 +1675,7 @@ vips_image_temp_name( char *name, int size )
{
static int global_serial = 0;
/* Old glibs named this differently.
*/
int serial =
#if GLIB_CHECK_VERSION( 2, 30, 0 )
g_atomic_int_add( &global_serial, 1 );
#else
g_atomic_int_exchange_and_add( &global_serial, 1 );
#endif
int serial = g_atomic_int_add( &global_serial, 1 );
vips_snprintf( name, size, "temp-%d", serial );
}
@ -2514,12 +2506,11 @@ vips_get_disc_threshold( void )
*/
threshold = 100 * 1024 * 1024;
if( (env = g_getenv( "VIPS_DISC_THRESHOLD" ))
#if ENABLE_DEPRECATED
if( (env = g_getenv( "VIPS_DISC_THRESHOLD" )) ||
(env = g_getenv( "IM_DISC_THRESHOLD" )) )
#else
if( (env = g_getenv( "VIPS_DISC_THRESHOLD" )) )
|| (env = g_getenv( "IM_DISC_THRESHOLD" ))
#endif
)
threshold = vips__parse_size( env );
if( vips__disc_threshold )

View File

@ -290,24 +290,6 @@ empty_log_handler( const gchar *log_domain, GLogLevelFlags log_level,
{
}
#if !GLIB_CHECK_VERSION( 2, 31, 0 )
static void
default_log_handler( const gchar *log_domain, GLogLevelFlags log_level,
const gchar *message, gpointer user_data )
{
if( log_level & (G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_INFO) ) {
const char *domains = g_getenv( "G_MESSAGES_DEBUG" );
if( !domains ||
(!g_str_equal( domains, "all" ) &&
!g_strrstr( domains, log_domain )) )
return;
}
g_log_default_handler( log_domain, log_level, message, user_data );
}
#endif /*!GLIB_CHECK_VERSION( 2, 31, 0 )*/
/* Attempt to set a minimum stacksize. This can be important on systems with a
* very low default, like musl.
*/
@ -407,7 +389,7 @@ vips_init( const char *argv0 )
return( 0 );
started = TRUE;
#ifdef OS_WIN32
#ifdef G_OS_WIN32
/* Windows has a limit of 512 files open at once for the fopen() family
* of functions, and 2048 for the _open() family. This raises the limit
* of fopen() to the same level as _open().
@ -415,7 +397,7 @@ vips_init( const char *argv0 )
* It will not go any higher than this, unfortunately.
*/
(void) _setmaxstdio( 2048 );
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
vips__threadpool_init();
vips__buffer_init();
@ -467,12 +449,11 @@ vips_init( const char *argv0 )
g_free( locale );
bind_textdomain_codeset( GETTEXT_PACKAGE, "UTF-8" );
if( g_getenv( "VIPS_INFO" )
#if ENABLE_DEPRECATED
if( g_getenv( "VIPS_INFO" ) ||
g_getenv( "IM_INFO" ) )
#else
if( g_getenv( "VIPS_INFO" ) )
|| g_getenv( "IM_INFO" )
#endif
)
vips_verbose();
if( g_getenv( "VIPS_PROFILE" ) )
vips_profile_set( TRUE );
@ -586,27 +567,14 @@ vips_init( const char *argv0 )
* set up if you are using libvips from something like Ruby. Allow this
* env var hack as a workaround.
*/
if( g_getenv( "VIPS_WARNING" )
#if ENABLE_DEPRECATED
if( g_getenv( "VIPS_WARNING" ) ||
g_getenv( "IM_WARNING" ) )
#else
if( g_getenv( "VIPS_WARNING" ) )
|| g_getenv( "IM_WARNING" )
#endif
)
g_log_set_handler( G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
empty_log_handler, NULL );
#if !GLIB_CHECK_VERSION( 2, 31, 0 )
/* Older glibs can sometimes show G_LOG_LEVEL_{INFO,DEBUG} messages.
* Block them ourselves. We test the env var inside the handler since
* vips_verbose() can be toggled at runtime.
*
* Again, we should not call g_log_set_handler(), but this is the only
* convenient way to fix this behaviour.
*/
g_log_set_handler( G_LOG_DOMAIN, G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG,
default_log_handler, NULL );
#endif /*!GLIB_CHECK_VERSION( 2, 31, 0 )*/
/* Set a minimum stacksize, if we can.
*/
if( (vips_min_stack_size = g_getenv( "VIPS_MIN_STACK_SIZE" )) )
@ -1057,7 +1025,7 @@ find_file( const char *name )
printf( "vips_guess_prefix: g_getenv( \"PATH\" ) == \"%s\"\n", path );
#endif /*DEBUG*/
#ifdef OS_WIN32
#ifdef G_OS_WIN32
{
char *dir;
@ -1068,9 +1036,9 @@ find_file( const char *name )
"%s" G_SEARCHPATH_SEPARATOR_S "%s", dir, path );
g_free( dir );
}
#else /*!OS_WIN32*/
#else /*!G_OS_WIN32*/
vips_strncpy( full_path, path, VIPS_PATH_MAX );
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
if( (prefix = scan_path( full_path, name )) )
return( prefix );
@ -1177,9 +1145,9 @@ vips_guess_prefix( const char *argv0, const char *env_name )
return( prefix );
}
#ifdef OS_WIN32
#ifdef G_OS_WIN32
prefix = vips__windows_prefix();
#else
#else /*!G_OS_WIN32*/
{
char *basename;
@ -1187,7 +1155,7 @@ vips_guess_prefix( const char *argv0, const char *env_name )
prefix = guess_prefix( argv0, basename );
g_free( basename );
}
#endif
#endif /*G_OS_WIN32*/
g_setenv( env_name, prefix, TRUE );

View File

@ -77,18 +77,16 @@
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /*HAVE_UNISTD_H*/
#ifdef OS_WIN32
#ifndef S_ISREG
#define S_ISREG(m) (!!(m & _S_IFREG))
#endif
#endif /*OS_WIN32*/
#include <vips/vips.h>
#ifdef OS_WIN32
#ifdef G_OS_WIN32
#ifndef S_ISREG
#define S_ISREG(m) (!!(m & _S_IFREG))
#endif
#include <windows.h>
#include <io.h>
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
/* Does this fd support mmap. Pipes won't, for example.
*/
@ -99,7 +97,7 @@ vips__mmap_supported( int fd )
size_t length = 4096;
off_t offset = 0;
#ifdef OS_WIN32
#ifdef G_OS_WIN32
{
HANDLE hFile = (HANDLE) _get_osfhandle( fd );
@ -128,7 +126,7 @@ vips__mmap_supported( int fd )
CloseHandle( hMMFile );
UnmapViewOfFile( baseaddr );
}
#else /*!OS_WIN32*/
#else /*!G_OS_WIN32*/
{
int prot = PROT_READ;
int flags = MAP_SHARED;
@ -138,7 +136,7 @@ vips__mmap_supported( int fd )
return( FALSE );
munmap( baseaddr, length );
}
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
return( TRUE );
}
@ -153,7 +151,7 @@ vips__mmap( int fd, int writeable, size_t length, gint64 offset )
length, offset );
#endif /*DEBUG*/
#ifdef OS_WIN32
#ifdef G_OS_WIN32
{
HANDLE hFile = (HANDLE) _get_osfhandle( fd );
@ -203,7 +201,7 @@ vips__mmap( int fd, int writeable, size_t length, gint64 offset )
*/
CloseHandle( hMMFile );
}
#else /*!OS_WIN32*/
#else /*!G_OS_WIN32*/
{
int prot;
int flags;
@ -237,7 +235,7 @@ vips__mmap( int fd, int writeable, size_t length, gint64 offset )
return( NULL );
}
}
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
return( baseaddr );
}
@ -245,19 +243,19 @@ vips__mmap( int fd, int writeable, size_t length, gint64 offset )
int
vips__munmap( const void *start, size_t length )
{
#ifdef OS_WIN32
#ifdef G_OS_WIN32
if( !UnmapViewOfFile( (void *) start ) ) {
vips_error_system( GetLastError(), "vips_mapfile",
"%s", _( "unable to UnmapViewOfFile" ) );
return( -1 );
}
#else /*!OS_WIN32*/
#else /*!G_OS_WIN32*/
if( munmap( (void *) start, length ) < 0 ) {
vips_error_system( errno, "vips_mapfile",
"%s", _( "unable to munmap file" ) );
return( -1 );
}
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
return( 0 );
}
@ -345,7 +343,7 @@ vips_remapfilerw( VipsImage *image )
printf( "vips_remapfilerw:\n" );
#endif /*DEBUG*/
#ifdef OS_WIN32
#ifdef G_OS_WIN32
{
HANDLE hFile = (HANDLE) _get_osfhandle( image->fd );
HANDLE hMMFile;
@ -377,7 +375,7 @@ vips_remapfilerw( VipsImage *image )
*/
CloseHandle( hMMFile );
}
#else /*!OS_WIN32*/
#else /*!G_OS_WIN32*/
{
assert( image->dtype == VIPS_IMAGE_MMAPIN );
@ -390,7 +388,7 @@ vips_remapfilerw( VipsImage *image )
return( -1 );
}
}
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
image->dtype = VIPS_IMAGE_MMAPINRW;

View File

@ -65,23 +65,24 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef OS_WIN32
#include <io.h>
#endif /*OS_WIN32*/
#include <vips/vips.h>
#include <vips/internal.h>
#include <vips/debug.h>
#ifdef G_OS_WIN32
#include <io.h>
#endif /*G_OS_WIN32*/
/* Try to make an O_BINARY ... sometimes need the leading '_'.
*/
#ifdef BINARY_OPEN
#ifdef G_PLATFORM_WIN32
#ifndef O_BINARY
#ifdef _O_BINARY
#define O_BINARY _O_BINARY
#endif /*_O_BINARY*/
#endif /*!O_BINARY*/
#endif /*BINARY_OPEN*/
#endif /*G_PLATFORM_WIN32*/
/* If we have O_BINARY, add it to a mode flags set.
*/
@ -307,12 +308,12 @@ vips_source_build( VipsObject *object )
connection->descriptor = dup( connection->descriptor );
connection->close_descriptor = connection->descriptor;
#ifdef OS_WIN32
#ifdef G_OS_WIN32
/* Windows will create eg. stdin and stdout in text mode.
* We always read in binary mode.
*/
_setmode( connection->descriptor, _O_BINARY );
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
}
if( vips_object_argument_isset( object, "blob" ) ) {
@ -564,8 +565,6 @@ vips_source_new_from_options( const char *options )
*
* Loaders should call this in response to the minimise signal on their output
* image.
*
* Returns: 0 on success, or -1 on error.
*/
void
vips_source_minimise( VipsSource *source )

View File

@ -55,23 +55,24 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef OS_WIN32
#include <io.h>
#endif /*OS_WIN32*/
#include <vips/vips.h>
#include <vips/internal.h>
#include <vips/debug.h>
#ifdef G_OS_WIN32
#include <io.h>
#endif /*G_OS_WIN32*/
/* Try to make an O_BINARY ... sometimes need the leading '_'.
*/
#ifdef BINARY_OPEN
#ifdef G_PLATFORM_WIN32
#ifndef O_BINARY
#ifdef _O_BINARY
#define O_BINARY _O_BINARY
#endif /*_O_BINARY*/
#endif /*!O_BINARY*/
#endif /*BINARY_OPEN*/
#endif /*G_PLATFORM_WIN32*/
/* If we have O_BINARY, add it to a mode flags set.
*/
@ -143,12 +144,12 @@ vips_target_build( VipsObject *object )
connection->descriptor = dup( connection->descriptor );
connection->close_descriptor = connection->descriptor;
#ifdef OS_WIN32
#ifdef G_OS_WIN32
/* Windows will create eg. stdin and stdout in text mode.
* We always write in binary mode.
*/
_setmode( connection->descriptor, _O_BINARY );
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
}
else if( target->memory )
target->memory_buffer = g_byte_array_new();

View File

@ -75,9 +75,9 @@
#include <vips/thread.h>
#include <vips/debug.h>
#ifdef OS_WIN32
#ifdef G_OS_WIN32
#include <windows.h>
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
/**
* SECTION: threadpool
@ -338,7 +338,7 @@ get_num_processors( void )
#endif /*G_OS_UNIX*/
#ifdef OS_WIN32
#ifdef G_OS_WIN32
{
/* Count the CPUs currently available to this process.
*/
@ -365,7 +365,7 @@ get_num_processors( void )
nproc = af_count;
}
}
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
return( nproc );
#endif /*!GLIB_CHECK_VERSION( 2, 48, 1 )*/
@ -406,13 +406,11 @@ vips_concurrency_get( void )
*/
if( vips__concurrency > 0 )
nthr = vips__concurrency;
else if( ((str = g_getenv( "VIPS_CONCURRENCY" ))
#if ENABLE_DEPRECATED
else if( ((str = g_getenv( "VIPS_CONCURRENCY" )) ||
(str = g_getenv( "IM_CONCURRENCY" ))) &&
#else
else if( (str = g_getenv( "VIPS_CONCURRENCY" )) &&
|| (str = g_getenv( "IM_CONCURRENCY" ))
#endif
(x = atoi( str )) > 0 )
) && (x = atoi( str )) > 0 )
nthr = x;
else
nthr = get_num_processors();

View File

@ -900,6 +900,21 @@ transform_array_int_g_string( const GValue *src_value, GValue *dest_value )
g_value_set_string( dest_value, vips_buf_all( &buf ) );
}
static void
transform_array_int_save_string( const GValue *src_value, GValue *dest_value )
{
GValue intermediate = { 0 };
g_value_init( &intermediate, G_TYPE_STRING );
transform_array_int_g_string( src_value, &intermediate );
vips_value_set_save_string( dest_value,
g_value_get_string( &intermediate ) );
g_value_unset( &intermediate );
}
/* It'd be great to be able to write a generic string->array function, but
* it doesn't seem possible.
*/
@ -951,6 +966,21 @@ transform_g_string_array_int( const GValue *src_value, GValue *dest_value )
g_free( str );
}
static void
transform_save_string_array_int( const GValue *src_value, GValue *dest_value )
{
GValue intermediate = { 0 };
g_value_init( &intermediate, G_TYPE_STRING );
g_value_set_string( &intermediate,
vips_value_get_save_string( src_value ) );
transform_g_string_array_int( &intermediate, dest_value );
g_value_unset( &intermediate );
}
/* We need a arrayint, we have an int, make a one-element array.
*/
static void
@ -1006,6 +1036,10 @@ vips_array_int_get_type( void )
transform_double_array_int );
g_value_register_transform_func( VIPS_TYPE_ARRAY_DOUBLE, type,
transform_array_double_array_int );
g_value_register_transform_func( type, VIPS_TYPE_SAVE_STRING,
transform_array_int_save_string );
g_value_register_transform_func( VIPS_TYPE_SAVE_STRING, type,
transform_save_string_array_int );
}
return( type );

View File

@ -53,27 +53,27 @@
#endif /*HAVE_IO_H*/
#include <fcntl.h>
#ifdef OS_WIN32
#include <windows.h>
#endif /*OS_WIN32*/
#include <vips/vips.h>
#include <vips/debug.h>
#include <vips/internal.h>
#ifdef G_OS_WIN32
#include <windows.h>
#endif /*G_OS_WIN32*/
/* Temp buffer for snprintf() layer on old systems.
*/
#define MAX_BUF (100000)
/* Try to make an O_BINARY ... sometimes need the leading '_'.
*/
#ifdef BINARY_OPEN
#ifdef G_PLATFORM_WIN32
#ifndef O_BINARY
#ifdef _O_BINARY
#define O_BINARY _O_BINARY
#endif /*_O_BINARY*/
#endif /*!O_BINARY*/
#endif /*BINARY_OPEN*/
#endif /*G_PLATFORM_WIN32*/
/* If we have O_BINARY, add it to a mode flags set.
*/
@ -562,15 +562,15 @@ vips_filename_suffix_match( const char *path, const char *suffixes[] )
gint64
vips_file_length( int fd )
{
#ifdef OS_WIN32
#ifdef G_OS_WIN32
struct _stati64 st;
if( _fstati64( fd, &st ) == -1 ) {
#else /*!OS_WIN32*/
#else /*!G_OS_WIN32*/
struct stat st;
if( fstat( fd, &st ) == -1 ) {
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
vips_error_system( errno, "vips_file_length",
"%s", _( "unable to get file stats" ) );
return( -1 );
@ -600,7 +600,7 @@ vips__write( int fd, const void *buf, size_t count )
return( 0 );
}
#ifdef OS_WIN32
#ifdef G_OS_WIN32
/* Set the create date on a file. On Windows, the create date may be copied
* over from an existing file of the same name, unless you reset it.
*
@ -619,7 +619,7 @@ vips__set_create_time( int fd )
SystemTimeToFileTime( &st, &ft );
SetFileTime( handle, &ft, &ft, &ft );
}
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
/* open() with a utf8 filename, setting errno.
*/
@ -638,10 +638,10 @@ vips__open( const char *filename, int flags, int mode )
fd = g_open( filename, flags, mode );
#ifdef OS_WIN32
#ifdef G_OS_WIN32
if( mode & O_CREAT )
vips__set_create_time( fd );
#endif
#endif /*G_OS_WIN32*/
return( fd );
}
@ -661,10 +661,10 @@ vips__fopen( const char *filename, const char *mode )
fp = g_fopen( filename, mode );
#ifdef OS_WIN32
#ifdef G_OS_WIN32
if( mode[0] == 'w' )
vips__set_create_time( _fileno( fp ) );
#endif
#endif /*G_OS_WIN32*/
return( fp );
}
@ -698,14 +698,14 @@ vips__file_open_read( const char *filename, const char *fallback_dir,
char *mode;
FILE *fp;
#ifdef BINARY_OPEN
#ifdef G_PLATFORM_WIN32
if( text_mode )
mode = "r";
else
mode = "rb";
#else /*BINARY_OPEN*/
#else /*!G_PLATFORM_WIN32*/
mode = "r";
#endif /*BINARY_OPEN*/
#endif /*G_PLATFORM_WIN32*/
if( (fp = vips__fopen( filename, mode )) )
return( fp );
@ -734,14 +734,14 @@ vips__file_open_write( const char *filename, gboolean text_mode )
char *mode;
FILE *fp;
#ifdef BINARY_OPEN
#ifdef G_PLATFORM_WIN32
if( text_mode )
mode = "w";
else
mode = "wb";
#else /*BINARY_OPEN*/
#else /*!G_PLATFORM_WIN32*/
mode = "w";
#endif /*BINARY_OPEN*/
#endif /*G_PLATFORM_WIN32*/
if( !(fp = vips__fopen( filename, mode )) ) {
vips_error_system( errno, "vips__file_open_write",
@ -1089,15 +1089,15 @@ vips__seek_no_error( int fd, gint64 pos, int whence )
{
gint64 new_pos;
#ifdef OS_WIN32
#ifdef G_OS_WIN32
new_pos = _lseeki64( fd, pos, whence );
#else /*!OS_WIN32*/
#else /*!G_OS_WIN32*/
/* On error, eg. opening a directory and seeking to the end, lseek()
* on linux seems to return 9223372036854775807 ((1 << 63) - 1)
* rather than (off_t) -1 for reasons I don't understand.
*/
new_pos = lseek( fd, pos, whence );
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
return( new_pos );
}
@ -1128,7 +1128,7 @@ vips__seek( int fd, gint64 pos, int whence )
int
vips__ftruncate( int fd, gint64 pos )
{
#ifdef OS_WIN32
#ifdef G_OS_WIN32
{
HANDLE hFile = (HANDLE) _get_osfhandle( fd );
@ -1140,13 +1140,13 @@ vips__ftruncate( int fd, gint64 pos )
return( -1 );
}
}
#else /*!OS_WIN32*/
#else /*!G_OS_WIN32*/
if( ftruncate( fd, pos ) ) {
vips_error_system( errno, "vips__ftruncate",
"%s", _( "unable to truncate" ) );
return( -1 );
}
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
return( 0 );
}
@ -1620,7 +1620,7 @@ vips__temp_dir( void )
const char *tmpd;
if( !(tmpd = g_getenv( "TMPDIR" )) ) {
#ifdef OS_WIN32
#ifdef G_OS_WIN32
static gboolean done = FALSE;
static char buf[256];
@ -1629,9 +1629,9 @@ vips__temp_dir( void )
strcpy( buf, "C:\\temp" );
}
tmpd = buf;
#else /*!OS_WIN32*/
#else /*!G_OS_WIN32*/
tmpd = "/tmp";
#endif /*!OS_WIN32*/
#endif /*!G_OS_WIN32*/
}
return( tmpd );
@ -1651,14 +1651,7 @@ vips__temp_name( const char *format )
char file2[FILENAME_MAX];
char *name;
/* Old glibs named this differently.
*/
int serial =
#if GLIB_CHECK_VERSION( 2, 30, 0 )
g_atomic_int_add( &global_serial, 1 );
#else
g_atomic_int_exchange_and_add( &global_serial, 1 );
#endif
int serial = g_atomic_int_add( &global_serial, 1 );
vips_snprintf( file, FILENAME_MAX, "vips-%d-%u",
serial, g_random_int() );
@ -1961,7 +1954,7 @@ vips__random_add( guint32 seed, int value )
static void *
vips_icc_dir_once( void *null )
{
#ifdef OS_WIN32
#ifdef G_OS_WIN32
/* From glib get_windows_directory_root()
*/
wchar_t wwindowsdir[MAX_PATH];
@ -1983,7 +1976,7 @@ vips_icc_dir_once( void *null )
return( (void *) full_path );
}
}
#endif
#endif /*G_OS_WIN32*/
return( (void *) VIPS_ICC_DIR );
}
@ -1997,7 +1990,7 @@ vips__icc_dir( void )
vips_icc_dir_once, NULL ) );
}
#ifdef OS_WIN32
#ifdef G_OS_WIN32
static HMODULE vips__dll = NULL;
#ifdef DLL_EXPORT
BOOL WINAPI
@ -2009,19 +2002,19 @@ DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
return( TRUE );
}
#endif
#endif
#endif /*G_OS_WIN32*/
static void *
vips__windows_prefix_once( void *null )
{
char *prefix;
#ifdef OS_WIN32
#ifdef G_OS_WIN32
prefix = g_win32_get_package_installation_directory_of_module(
vips__dll );
#else
#else /*!G_OS_WIN32*/
prefix = (char *) g_getenv( "VIPSHOME" );
#endif
#endif /*G_OS_WIN32*/
return( (void *) prefix );
}

View File

@ -102,12 +102,11 @@ vips_vector_init( void )
/* Look for the environment variable VIPS_NOVECTOR and use that to turn
* off as well.
*/
if( g_getenv( "VIPS_NOVECTOR" )
#if ENABLE_DEPRECATED
if( g_getenv( "VIPS_NOVECTOR" ) ||
g_getenv( "IM_NOVECTOR" ) )
#else
if( g_getenv( "VIPS_NOVECTOR" ) )
|| g_getenv( "IM_NOVECTOR" )
#endif
)
vips__vector_enabled = FALSE;
#endif /*HAVE_ORC*/

View File

@ -115,13 +115,13 @@
/* Try to make an O_BINARY ... sometimes need the leading '_'.
*/
#ifdef BINARY_OPEN
#ifdef G_PLATFORM_WIN32
#ifndef O_BINARY
#ifdef _O_BINARY
#define O_BINARY _O_BINARY
#endif /*_O_BINARY*/
#endif /*!O_BINARY*/
#endif /*BINARY_OPEN*/
#endif /*G_PLATFORM_WIN32*/
/* If we have O_BINARY, add it to a mode flags set.
*/

View File

@ -58,9 +58,9 @@
#include <vips/internal.h>
#include <vips/thread.h>
#ifdef OS_WIN32
#ifdef G_OS_WIN32
#include <windows.h>
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
/* Sanity checking ... write to this during read tests to make sure we don't
* get optimized out.
@ -189,15 +189,15 @@ vips_getpagesize( void )
static int pagesize = 0;
if( !pagesize ) {
#ifdef OS_WIN32
#ifdef G_OS_WIN32
SYSTEM_INFO si;
GetSystemInfo( &si );
pagesize = si.dwAllocationGranularity;
#else /*OS_WIN32*/
#else /*!G_OS_WIN32*/
pagesize = getpagesize();
#endif /*OS_WIN32*/
#endif /*G_OS_WIN32*/
#ifdef DEBUG_TOTAL
printf( "vips_getpagesize: 0x%x\n", pagesize );

View File

@ -1123,16 +1123,9 @@ vips__add_mosaic_name( VipsImage *image )
{
static int global_serial = 0;
/* Old glibs named this differently.
*
* TODO(kleisauke): Could we call vips_image_temp_name instead?
/* TODO(kleisauke): Could we call vips_image_temp_name instead?
*/
int serial =
#if GLIB_CHECK_VERSION( 2, 30, 0 )
g_atomic_int_add( &global_serial, 1 );
#else
g_atomic_int_exchange_and_add( &global_serial, 1 );
#endif
int serial = g_atomic_int_add( &global_serial, 1 );
char name[256];

View File

@ -54,10 +54,6 @@
#include "templates.h"
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif /*WITH_DMALLOC*/
#define VIPS_TYPE_INTERPOLATE_BICUBIC \
(vips_interpolate_bicubic_get_type())
#define VIPS_INTERPOLATE_BICUBIC( obj ) \

View File

@ -136,11 +136,11 @@ typedef struct _VipsThumbnail {
int heif_thumbnail_width;
int heif_thumbnail_height;
/* For TIFF sources, open subifds to get pyr layers.
/* Pyramids are stored in subifds.
*/
gboolean subifd_pyramid;
/* For TIFF sources, open pages to get pyr layers.
/* Pyramids are stored in pages.
*/
gboolean page_pyramid;
@ -250,18 +250,18 @@ vips_thumbnail_read_header( VipsThumbnail *thumbnail, VipsImage *image )
}
}
/* Detect a TIFF pyramid made of pages following a roughly /2 shrink.
/* Detect a pyramid made of pages following a roughly /2 shrink.
*
* This may not be a pyr tiff, so no error if we can't find the layers.
*/
static void
vips_thumbnail_get_tiff_pyramid_page( VipsThumbnail *thumbnail )
vips_thumbnail_get_pyramid_page( VipsThumbnail *thumbnail )
{
VipsThumbnailClass *class = VIPS_THUMBNAIL_GET_CLASS( thumbnail );
int i;
#ifdef DEBUG
printf( "vips_thumbnail_get_tiff_pyramid_page:\n" );
printf( "vips_thumbnail_get_pyramid_page:\n" );
#endif /*DEBUG*/
/* Single-page docs can't be pyramids.
@ -301,7 +301,7 @@ vips_thumbnail_get_tiff_pyramid_page( VipsThumbnail *thumbnail )
/* Now set level_count. This signals that we've found a pyramid.
*/
#ifdef DEBUG
printf( "vips_thumbnail_get_tiff_pyramid_page: "
printf( "vips_thumbnail_get_pyramid_page: "
"%d layer pyramid detected\n",
thumbnail->n_pages );
#endif /*DEBUG*/
@ -500,7 +500,7 @@ vips_thumbnail_find_jpegshrink( VipsThumbnail *thumbnail,
return( 1 );
}
/* Find the best pyramid (openslide or tiff) level.
/* Find the best pyramid (openslide, tiff, etc.) level.
*/
static int
vips_thumbnail_find_pyrlevel( VipsThumbnail *thumbnail,
@ -553,7 +553,21 @@ vips_thumbnail_open( VipsThumbnail *thumbnail )
thumbnail->subifd_pyramid = FALSE;
thumbnail->page_pyramid = TRUE;
vips_thumbnail_get_tiff_pyramid_page( thumbnail );
vips_thumbnail_get_pyramid_page( thumbnail );
if( thumbnail->level_count == 0 )
thumbnail->page_pyramid = FALSE;
}
}
/* jp2k uses page-based pyramids.
*/
if( vips_isprefix( "VipsForeignLoadJp2k", thumbnail->loader ) ) {
if( thumbnail->level_count == 0 ) {
thumbnail->subifd_pyramid = FALSE;
thumbnail->page_pyramid = TRUE;
vips_thumbnail_get_pyramid_page( thumbnail );
if( thumbnail->level_count == 0 )
thumbnail->page_pyramid = FALSE;
@ -576,8 +590,9 @@ vips_thumbnail_open( VipsThumbnail *thumbnail )
factor = vips_thumbnail_find_jpegshrink( thumbnail,
thumbnail->input_width, thumbnail->input_height );
else if( vips_isprefix( "VipsForeignLoadTiff", thumbnail->loader ) ||
vips_isprefix( "VipsForeignLoadJp2k", thumbnail->loader ) ||
vips_isprefix( "VipsForeignLoadOpenslide",
thumbnail->loader ) ) {
thumbnail->loader ) ) {
if( thumbnail->level_count > 0 )
factor = vips_thumbnail_find_pyrlevel( thumbnail,
thumbnail->input_width,
@ -685,6 +700,10 @@ vips_thumbnail_build( VipsObject *object )
in = t[12];
}
/* Note the interpretation we will revert to after linear.
*/
input_interpretation = in->Type;
/* In linear mode, we need to transform to a linear space before
* vips_resize().
*/
@ -719,11 +738,6 @@ vips_thumbnail_build( VipsObject *object )
*/
VipsInterpretation interpretation;
/* Note the interpretation we will revert to after
* linear.
*/
input_interpretation = in->Type;
if( in->Bands < 3 )
interpretation = VIPS_INTERPRETATION_GREY16;
else
@ -877,13 +891,13 @@ vips_thumbnail_build( VipsObject *object )
thumbnail->export_profile );
if( vips_colourspace( in, &t[7],
VIPS_INTERPRETATION_XYZ, NULL ) ||
vips_icc_export( t[7], &t[8],
vips_icc_export( t[7], &t[10],
"output_profile",
thumbnail->export_profile,
"intent", thumbnail->intent,
NULL ) )
return( -1 );
in = t[8];
in = t[10];
}
}
else if( thumbnail->linear ) {
@ -1113,7 +1127,19 @@ vips_thumbnail_file_open( VipsThumbnail *thumbnail, double factor )
"scale", 1.0 / factor,
NULL ) );
}
else if( vips_isprefix( "VipsForeignLoadJp2k", thumbnail->loader ) ) {
/* jp2k optionally uses page-based pyramids.
*/
if( thumbnail->page_pyramid )
return( vips_image_new_from_file( file->filename,
"access", VIPS_ACCESS_SEQUENTIAL,
"page", (int) factor,
NULL ) );
else
return( vips_image_new_from_file( file->filename,
"access", VIPS_ACCESS_SEQUENTIAL,
NULL ) );
}
else if( vips_isprefix( "VipsForeignLoadTiff", thumbnail->loader ) ) {
/* We support three modes: subifd pyramids, page-based
* pyramids, and simple multi-page TIFFs (no pyramid).
@ -1133,7 +1159,6 @@ vips_thumbnail_file_open( VipsThumbnail *thumbnail, double factor )
"access", VIPS_ACCESS_SEQUENTIAL,
NULL ) );
}
else if( vips_isprefix( "VipsForeignLoadHeif", thumbnail->loader ) ) {
return( vips_image_new_from_file( file->filename,
"access", VIPS_ACCESS_SEQUENTIAL,
@ -1326,6 +1351,23 @@ vips_thumbnail_buffer_open( VipsThumbnail *thumbnail, double factor )
"scale", 1.0 / factor,
NULL ) );
}
else if( vips_isprefix( "VipsForeignLoadJp2k", thumbnail->loader ) ) {
/* Optional page-based pyramids.
*/
if( thumbnail->page_pyramid )
return( vips_image_new_from_buffer(
buffer->buf->data, buffer->buf->length,
buffer->option_string,
"access", VIPS_ACCESS_SEQUENTIAL,
"page", (int) factor,
NULL ) );
else
return( vips_image_new_from_buffer(
buffer->buf->data, buffer->buf->length,
buffer->option_string,
"access", VIPS_ACCESS_SEQUENTIAL,
NULL ) );
}
else if( vips_isprefix( "VipsForeignLoadTiff", thumbnail->loader ) ) {
/* We support three modes: subifd pyramids, page-based
* pyramids, and simple multi-page TIFFs (no pyramid).
@ -1522,6 +1564,23 @@ vips_thumbnail_source_open( VipsThumbnail *thumbnail, double factor )
"scale", 1.0 / factor,
NULL ) );
}
else if( vips_isprefix( "VipsForeignLoadJp2k", thumbnail->loader ) ) {
/* Optional page-based pyramids.
*/
if( thumbnail->page_pyramid )
return( vips_image_new_from_source(
source->source,
source->option_string,
"access", VIPS_ACCESS_SEQUENTIAL,
"page", (int) factor,
NULL ) );
else
return( vips_image_new_from_source(
source->source,
source->option_string,
"access", VIPS_ACCESS_SEQUENTIAL,
NULL ) );
}
else if( vips_isprefix( "VipsForeignLoadTiff", thumbnail->loader ) ) {
/* We support three modes: subifd pyramids, page-based
* pyramids, and simple multi-page TIFFs (no pyramid).

View File

@ -2,11 +2,9 @@ cplusplus/include/vips/VConnection8.h
cplusplus/include/vips/VError8.h
cplusplus/include/vips/VImage8.h
cplusplus/include/vips/VInterpolate8.h
cplusplus/include/vips/vips-operators.h
libvips/include/vips/arithmetic.h
libvips/include/vips/basic.h
libvips/include/vips/buf.h
libvips/include/vips/cimg_funcs.h
libvips/include/vips/colour.h
libvips/include/vips/connection.h
libvips/include/vips/conversion.h
@ -237,7 +235,6 @@ libvips/foreign/fits.c
libvips/foreign/fitsload.c
libvips/foreign/fitssave.c
libvips/foreign/foreign.c
libvips/foreign/gifload.c
libvips/foreign/heifload.c
libvips/foreign/heifsave.c
libvips/foreign/jpeg2vips.c
@ -254,6 +251,7 @@ libvips/foreign/matrixload.c
libvips/foreign/matrixsave.c
libvips/foreign/niftiload.c
libvips/foreign/niftisave.c
libvips/foreign/nsgifload.c
libvips/foreign/openexr2vips.c
libvips/foreign/openexrload.c
libvips/foreign/openslide2vips.c
@ -285,6 +283,8 @@ libvips/foreign/vipssave.c
libvips/foreign/webp2vips.c
libvips/foreign/webpload.c
libvips/foreign/webpsave.c
libvips/foreign/libnsgif/libnsgif.c
libvips/foreign/libnsgif/lzw.c
libvips/freqfilt/freqfilt.c
libvips/freqfilt/freqmult.c
libvips/freqfilt/fwfft.c
@ -333,6 +333,7 @@ libvips/iofuncs/sinkmemory.c
libvips/iofuncs/sinkscreen.c
libvips/iofuncs/source.c
libvips/iofuncs/sourcecustom.c
libvips/iofuncs/sourceginput.c
libvips/iofuncs/system.c
libvips/iofuncs/target.c
libvips/iofuncs/targetcustom.c

View File

@ -56,6 +56,7 @@ MOSAIC_MARKS = [[489, 140], [66, 141],
MOSAIC_VERTICAL_MARKS = [[388, 44], [364, 346],
[384, 17], [385, 629],
[527, 42], [503, 959]]
JP2K_FILE = os.path.join(IMAGES, "world.jp2")
unsigned_formats = [pyvips.BandFormat.UCHAR,
pyvips.BandFormat.USHORT,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

View File

@ -1,5 +1,4 @@
# vim: set fileencoding=utf-8 :
import filecmp
import sys
import os
import shutil
@ -18,7 +17,7 @@ from helpers import \
GIF_ANIM_DISPOSE_PREVIOUS_EXPECTED_PNG_FILE, \
temp_filename, assert_almost_equal_objects, have, skip_if_no, \
TIF1_FILE, TIF2_FILE, TIF4_FILE, WEBP_LOOKS_LIKE_SVG_FILE, \
WEBP_ANIMATED_FILE
WEBP_ANIMATED_FILE, JP2K_FILE
class TestForeign:
tempdir = None
@ -38,7 +37,7 @@ class TestForeign:
cls.cmyk.remove("icc-profile-data")
im = pyvips.Image.new_from_file(GIF_FILE)
cls.onebit = im > 128
cls.onebit = im[1] > 128
@classmethod
def teardown_class(cls):
@ -681,10 +680,14 @@ class TestForeign:
x1 = pyvips.Image.new_from_file(GIF_ANIM_FILE, n=-1)
w1 = x1.webpsave_buffer(Q=10)
# our test gif has delay 0 for the first frame set in error,
# when converting to WebP this should result in a 100ms delay.
expected_delay = [100 if d <= 10 else d for d in x1.get("delay")]
x2 = pyvips.Image.new_from_buffer(w1, "", n=-1)
assert x1.width == x2.width
assert x1.height == x2.height
assert x1.get("delay") == x2.get("delay")
assert expected_delay == x2.get("delay")
assert x1.get("page-height") == x2.get("page-height")
assert x1.get("gif-loop") == x2.get("gif-loop")
@ -800,61 +803,53 @@ class TestForeign:
def test_gifload(self):
def gif_valid(im):
a = im(10, 10)
assert_almost_equal_objects(a, [33])
assert_almost_equal_objects(a, [33, 33, 33, 255])
assert im.width == 159
assert im.height == 203
assert im.bands == 1
assert im.bands == 4
self.file_loader("gifload", GIF_FILE, gif_valid)
self.buffer_loader("gifload_buffer", GIF_FILE, gif_valid)
# 'n' param added in 8.5
if pyvips.at_least_libvips(8, 5):
x1 = pyvips.Image.new_from_file(GIF_ANIM_FILE)
x2 = pyvips.Image.new_from_file(GIF_ANIM_FILE, n=2)
assert x2.height == 2 * x1.height
page_height = x2.get("page-height")
assert page_height == x1.height
# test metadata
x2 = pyvips.Image.new_from_file(GIF_ANIM_FILE, n=-1)
# our test gif has delay 0 for the first frame set in error
assert x2.get("delay") == [0, 50, 50, 50, 50]
assert x2.get("loop") == 32760
assert x2.get("background") == [255, 255, 255]
# test deprecated fields too
assert x2.get("gif-loop") == 32759
assert x2.get("gif-delay") == 0
x2 = pyvips.Image.new_from_file(GIF_ANIM_FILE, n=-1)
assert x2.height == 5 * x1.height
# our test gif has delay 0 for the first frame set in error
assert x2.get("delay") == [0, 50, 50, 50, 50]
# test every pixel
x1 = pyvips.Image.new_from_file(GIF_ANIM_FILE, n=-1)
x2 = pyvips.Image.new_from_file(GIF_ANIM_EXPECTED_PNG_FILE)
assert (x1 - x2).abs().max() == 0
x2 = pyvips.Image.new_from_file(GIF_ANIM_FILE, page=1, n=-1)
assert x2.height == 4 * x1.height
# test page handling
x1 = pyvips.Image.new_from_file(GIF_ANIM_FILE)
x2 = pyvips.Image.new_from_file(GIF_ANIM_FILE, n=2)
assert x2.height == 2 * x1.height
page_height = x2.get("page-height")
assert page_height == x1.height
animation = pyvips.Image.new_from_file(GIF_ANIM_FILE, n=-1)
filename = temp_filename(self.tempdir, '.png')
animation.write_to_file(filename)
# Uncomment to see output file
# animation.write_to_file('cogs.png')
x2 = pyvips.Image.new_from_file(GIF_ANIM_FILE, n=-1)
assert x2.height == 5 * x1.height
assert filecmp.cmp(GIF_ANIM_EXPECTED_PNG_FILE, filename, shallow=False)
x2 = pyvips.Image.new_from_file(GIF_ANIM_FILE, page=1, n=-1)
assert x2.height == 4 * x1.height
@skip_if_no("gifload")
def test_gifload_animation_dispose_background(self):
animation = pyvips.Image.new_from_file(GIF_ANIM_DISPOSE_BACKGROUND_FILE, n=-1)
filename = temp_filename(self.tempdir, '.png')
animation.write_to_file(filename)
# Uncomment to see output file
# animation.write_to_file('dispose-background.png')
assert filecmp.cmp(GIF_ANIM_DISPOSE_BACKGROUND_EXPECTED_PNG_FILE, filename, shallow=False)
x1 = pyvips.Image.new_from_file(GIF_ANIM_DISPOSE_BACKGROUND_FILE, n=-1)
x2 = pyvips.Image.new_from_file(GIF_ANIM_DISPOSE_BACKGROUND_EXPECTED_PNG_FILE)
assert (x1 - x2).abs().max() == 0
@skip_if_no("gifload")
def test_gifload_animation_dispose_previous(self):
animation = pyvips.Image.new_from_file(GIF_ANIM_DISPOSE_PREVIOUS_FILE, n=-1)
filename = temp_filename(self.tempdir, '.png')
animation.write_to_file(filename)
# Uncomment to see output file
# animation.write_to_file('dispose-previous.png')
assert filecmp.cmp(GIF_ANIM_DISPOSE_PREVIOUS_EXPECTED_PNG_FILE, filename, shallow=False)
x1 = pyvips.Image.new_from_file(GIF_ANIM_DISPOSE_PREVIOUS_FILE, n=-1)
x2 = pyvips.Image.new_from_file(GIF_ANIM_DISPOSE_PREVIOUS_EXPECTED_PNG_FILE)
assert (x1 - x2).abs().max() == 0
@skip_if_no("svgload")
def test_svgload(self):
@ -1132,6 +1127,54 @@ class TestForeign:
y = pyvips.Image.new_from_buffer(buf, "")
assert y.get("exif-ifd0-Make").split(" ")[0] == "banana"
@skip_if_no("jp2kload")
def test_jp2kload(self):
def jp2k_valid(im):
a = im(402, 73)
assert_almost_equal_objects(a, [141, 144, 73], threshold=2)
assert im.width == 800
assert im.height == 400
assert im.bands == 3
self.file_loader("jp2kload", JP2K_FILE, jp2k_valid)
self.buffer_loader("jp2kload_buffer", JP2K_FILE, jp2k_valid)
@skip_if_no("jp2ksave")
def test_jp2ksave(self):
self.save_load_buffer("jp2ksave_buffer", "jp2kload_buffer",
self.colour, 80)
buf = self.colour.jp2ksave_buffer(lossless=True)
im2 = pyvips.Image.new_from_buffer(buf, "")
assert (self.colour == im2).min() == 255
# higher Q should mean a bigger buffer
b1 = self.mono.jp2ksave_buffer(Q=10)
b2 = self.mono.jp2ksave_buffer(Q=90)
assert len(b2) > len(b1)
# disabling chroma subsample should mean a bigger buffer
b1 = self.colour.jp2ksave_buffer(subsample_mode="on")
b2 = self.colour.jp2ksave_buffer(subsample_mode="off")
assert len(b2) > len(b1)
# enabling lossless should mean a bigger buffer
b1 = self.colour.jp2ksave_buffer(lossless=False)
b2 = self.colour.jp2ksave_buffer(lossless=True)
assert len(b2) > len(b1)
# 16-bit colour load and save
im = self.colour.colourspace("rgb16")
buf = im.jp2ksave_buffer(lossless=True)
im2 = pyvips.Image.new_from_buffer(buf, "")
assert (im == im2).min() == 255
# openjpeg 32-bit load and save doesn't seem to work, comment out
# im = self.colour.colourspace("rgb16").cast("uint") << 14
# buf = im.jp2ksave_buffer(lossless=True)
# im2 = pyvips.Image.new_from_buffer(buf, "")
# assert (im == im2).min() == 255
if __name__ == '__main__':
pytest.main()

View File

@ -101,9 +101,9 @@
#include <vips/vips7compat.h>
#endif
#ifdef OS_WIN32
#ifdef G_OS_WIN32
#define strcasecmp(a,b) _stricmp(a,b)
#endif
#endif /*G_OS_WIN32*/
static char *main_option_plugin = NULL;
static gboolean main_option_version;
@ -458,11 +458,11 @@ parse_options( GOptionContext *context, int *argc, char **argv )
"OPER", _( "execute vips operation OPER" ) );
g_option_context_set_summary( context, vips_buf_all( &buf ) );
#ifdef HAVE_G_WIN32_GET_COMMAND_LINE
#ifdef G_OS_WIN32
if( !g_option_context_parse_strv( context, &argv, &error ) )
#else /*!HAVE_G_WIN32_GET_COMMAND_LINE*/
#else /*!G_OS_WIN32*/
if( !g_option_context_parse( context, argc, &argv, &error ) )
#endif /*HAVE_G_WIN32_GET_COMMAND_LINE*/
#endif /*G_OS_WIN32*/
{
if( error ) {
fprintf( stderr, "%s\n", error->message );
@ -531,9 +531,9 @@ main( int argc, char **argv )
/* On Windows, argv is ascii-only .. use this to get a utf-8 version of
* the args.
*/
#ifdef HAVE_G_WIN32_GET_COMMAND_LINE
#ifdef G_OS_WIN32
argv = g_win32_get_command_line();
#endif /*HAVE_G_WIN32_GET_COMMAND_LINE*/
#endif /*G_OS_WIN32*/
#ifdef DEBUG_FATAL
/* Set masks for debugging ... stop on any problem.
@ -582,11 +582,11 @@ main( int argc, char **argv )
*/
g_option_context_set_help_enabled( context, FALSE );
#ifdef HAVE_G_WIN32_GET_COMMAND_LINE
#ifdef G_OS_WIN32
if( !g_option_context_parse_strv( context, &argv, &error ) )
#else /*!HAVE_G_WIN32_GET_COMMAND_LINE*/
#else /*!G_OS_WIN32*/
if( !g_option_context_parse( context, &argc, &argv, &error ) )
#endif /*HAVE_G_WIN32_GET_COMMAND_LINE*/
#endif /*G_OS_WIN32*/
{
if( error ) {
fprintf( stderr, "%s\n", error->message );
@ -753,9 +753,9 @@ main( int argc, char **argv )
g_option_context_free( context );
#ifdef HAVE_G_WIN32_GET_COMMAND_LINE
#ifdef G_OS_WIN32
g_strfreev( argv );
#endif /*HAVE_G_WIN32_GET_COMMAND_LINE*/
#endif /*G_OS_WIN32*/
vips_shutdown();

View File

@ -141,9 +141,9 @@ main( int argc, char **argv )
/* On Windows, argv is ascii-only .. use this to get a utf-8 version of
* the args.
*/
#ifdef HAVE_G_WIN32_GET_COMMAND_LINE
#ifdef G_OS_WIN32
argv = g_win32_get_command_line();
#endif /*HAVE_G_WIN32_GET_COMMAND_LINE*/
#endif /*G_OS_WIN32*/
context = g_option_context_new(
_( "vipsedit - edit vips file header" ) );
@ -153,11 +153,11 @@ main( int argc, char **argv )
g_option_group_set_translation_domain( main_group, GETTEXT_PACKAGE );
g_option_context_set_main_group( context, main_group );
#ifdef HAVE_G_WIN32_GET_COMMAND_LINE
#ifdef G_OS_WIN32
if( !g_option_context_parse_strv( context, &argv, &error ) )
#else /*!HAVE_G_WIN32_GET_COMMAND_LINE*/
#else /*!G_OS_WIN32*/
if( !g_option_context_parse( context, &argc, &argv, &error ) )
#endif /*HAVE_G_WIN32_GET_COMMAND_LINE*/
#endif /*G_OS_WIN32*/
{
vips_g_error( &error );
@ -272,9 +272,9 @@ main( int argc, char **argv )
g_option_context_free( context );
#ifdef HAVE_G_WIN32_GET_COMMAND_LINE
#ifdef G_OS_WIN32
g_strfreev( argv );
#endif /*HAVE_G_WIN32_GET_COMMAND_LINE*/
#endif /*G_OS_WIN32*/
vips_shutdown();

View File

@ -180,9 +180,9 @@ main( int argc, char *argv[] )
/* On Windows, argv is ascii-only .. use this to get a utf-8 version of
* the args.
*/
#ifdef HAVE_G_WIN32_GET_COMMAND_LINE
#ifdef G_OS_WIN32
argv = g_win32_get_command_line();
#endif /*HAVE_G_WIN32_GET_COMMAND_LINE*/
#endif /*G_OS_WIN32*/
context = g_option_context_new( _( "- print image header" ) );
main_group = g_option_group_new( NULL, NULL, NULL, NULL, NULL );
@ -191,11 +191,11 @@ main( int argc, char *argv[] )
g_option_group_set_translation_domain( main_group, GETTEXT_PACKAGE );
g_option_context_set_main_group( context, main_group );
#ifdef HAVE_G_WIN32_GET_COMMAND_LINE
#ifdef G_OS_WIN32
if( !g_option_context_parse_strv( context, &argv, &error ) )
#else /*!HAVE_G_WIN32_GET_COMMAND_LINE*/
#else /*!G_OS_WIN32*/
if( !g_option_context_parse( context, &argc, &argv, &error ) )
#endif /*HAVE_G_WIN32_GET_COMMAND_LINE*/
#endif /*G_OS_WIN32*/
{
if( error ) {
fprintf( stderr, "%s\n", error->message );
@ -247,9 +247,9 @@ main( int argc, char *argv[] )
/* We don't free this on error exit, sadly.
*/
#ifdef HAVE_G_WIN32_GET_COMMAND_LINE
#ifdef G_OS_WIN32
g_strfreev( argv );
#endif /*HAVE_G_WIN32_GET_COMMAND_LINE*/
#endif /*G_OS_WIN32*/
vips_shutdown();

View File

@ -500,9 +500,9 @@ main( int argc, char **argv )
/* On Windows, argv is ascii-only .. use this to get a utf-8 version of
* the args.
*/
#ifdef HAVE_G_WIN32_GET_COMMAND_LINE
#ifdef G_OS_WIN32
argv = g_win32_get_command_line();
#endif /*HAVE_G_WIN32_GET_COMMAND_LINE*/
#endif /*G_OS_WIN32*/
context = g_option_context_new( _( "- thumbnail generator" ) );
@ -512,11 +512,11 @@ main( int argc, char **argv )
g_option_group_set_translation_domain( main_group, GETTEXT_PACKAGE );
g_option_context_set_main_group( context, main_group );
#ifdef HAVE_G_WIN32_GET_COMMAND_LINE
#ifdef G_OS_WIN32
if( !g_option_context_parse_strv( context, &argv, &error ) )
#else /*!HAVE_G_WIN32_GET_COMMAND_LINE*/
#else /*!G_OS_WIN32*/
if( !g_option_context_parse( context, &argc, &argv, &error ) )
#endif /*HAVE_G_WIN32_GET_COMMAND_LINE*/
#endif /*G_OS_WIN32*/
{
if( error ) {
fprintf( stderr, "%s\n", error->message );
@ -563,9 +563,9 @@ main( int argc, char **argv )
/* We don't free this on error exit, sadly.
*/
#ifdef HAVE_G_WIN32_GET_COMMAND_LINE
#ifdef G_OS_WIN32
g_strfreev( argv );
#endif /*HAVE_G_WIN32_GET_COMMAND_LINE*/
#endif /*G_OS_WIN32*/
vips_shutdown();