diff --git a/ChangeLog b/ChangeLog
index 4c5f5675..9ae3b73a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -9,6 +9,11 @@
- now (more or less) passes -Wextra
- added "fail" option to im_jpeg2vips: fail with an error on any warning
(thank you Ole)
+- started gtk-doc changes
+- renamed im_meta_get_type() and im_header_get_type() as
+ im_meta_get_typeof() and im_header_get_typeof() to prevent confusion with
+ GObject type definers (was breaking gtkdoc object scan)
+- revised more names, limited documented API
- im_buildlut() could segv for non-zero based tables (thanks Jack)
- VIPS_BUF_STATIC() does not take length arg
- check for SetImageOption() so we work with GraphicsMagick too
diff --git a/Makefile.am b/Makefile.am
index c3da22fa..fe2dae28 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,24 +1,24 @@
# only build in the python dir if we can
if HAVE_PYTHON
-P_COMPILE_DIR = python
+P_COMPILE_DIR = swig
P_DIST_DIR =
else
P_COMPILE_DIR =
-P_DIST_DIR = python
+P_DIST_DIR = swig
endif
SUBDIRS = \
- libsrc \
- src \
- include \
- libsrcCC \
+ libvips \
+ tools \
+ libvipsCC \
contrib \
man \
po \
+ doc \
$(P_COMPILE_DIR)
EXTRA_DIST = \
- doc \
+ m4 \
benchmark \
bootstrap.sh \
vipsCC-7.${IM_MINOR_VERSION}.pc.in \
@@ -45,3 +45,4 @@ uninstall-hook:
-chmod -R u+w ${DESTDIR}$(datadir)/doc/vips
-rm -rf ${DESTDIR}$(datadir)/doc/vips
+DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc
diff --git a/TODO b/TODO
index a4da98eb..c6526f8c 100644
--- a/TODO
+++ b/TODO
@@ -36,7 +36,59 @@
- COPYInG file should be lgpl2.1+? seems to be plain 2.1 atm
-- look at gtk-doc? installed now
+- need a separate sectrion in ref docs for vips, vipsCC (and python?)
+
+- try the new liboil thing:
+
+ http://www.schleef.org/orc/
+
+ pick something like abs and time it
+
+
+- im__cast_and_call() no longer does
+
+ out->Bbits = im_bits_of_fmt( out->BandFmt );
+
+ make sure we do this for each use of im__cast_and_call()
+
+- im__cast_and_call() no longer casts input to output type, it casts inputs
+ up to the smallest common type
+
+ so we need to change all the buffer processors from
+
+ T op T -> T
+
+ to
+
+ T1 op T1 -> T2
+
+
+
+
+
+
+- split proto.h into headers for arithmetic etc.
+
+- move headers into libsrc/arithmetic, can we get them installed into the
+ right prefix?
+
+- move VImage.h into libsrcCC
+
+- rename libsrc as libvips
+
+- rename src as vipstools
+
+- rename libsrcCC as libvipsCC
+
+- rename python as SWIG
+
+- rename vipsCC in SWIG as pyvips
+
+
+
+
+
+
- try the new liboil thing:
diff --git a/bootstrap.sh b/bootstrap.sh
index 1ed3e0b7..d5b9a7fb 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -8,10 +8,13 @@ rm -rf autom4te.cache
rm -f config.* configure depcomp
rm -f install-sh intltool-* libtool ltmain.sh missing mkinstalldirs
rm -f stamp-* vipsCC-7.19.pc vips-7.19.spec vips-7.19.pc
-rm -f python/vipsCC/*.cxx
-rm -f python/vipsCC/VImage.h
-rm -f python/vipsCC/VImage.py python/vipsCC/VError.py python/vipsCC/VMask.py python/vipsCC/Display.py
+rm -f swig/vipsCC/*.cxx
+rm -f swig/vipsCC/VImage.h
+rm -f swig/vipsCC/VImage.py python/vipsCC/VError.py python/vipsCC/VMask.py python/vipsCC/Display.py
rm -f benchmark/temp*
+( cd doc ; mkdir poop ; mv reference/VIPS-docs.sgml.in poop ; mv reference/Makefile.am poop ; rm -rf reference/* ; mv poop/* reference ; rmdir poop )
+
+gtkdocize --copy --docdir doc/reference --flavour no-tmpl || exit 1
# some systems need libtoolize, some glibtoolize ... how annoying
echo testing for glibtoolize ...
@@ -32,4 +35,3 @@ autoconf
autoheader
$LIBTOOLIZE --copy --force --automake
automake --add-missing --copy
-
diff --git a/configure.in b/configure.in
index 72841f2f..39e8c53d 100644
--- a/configure.in
+++ b/configure.in
@@ -1,6 +1,7 @@
# Process this file with autoconf to produce a configure script.
-AC_INIT(include/vips/colour.h)
+AC_INIT(libvips/include/vips/colour.h)
AM_CONFIG_HEADER(config.h)
+AC_CONFIG_MACRO_DIR(m4)
# user-visible library versioning
IM_MAJOR_VERSION=7
@@ -204,6 +205,9 @@ if test x"$enable_threads" != "xno"; then
enable_threads=yes
fi
+# check for gtk-doc
+GTK_DOC_CHECK(1.9)
+
# optional supporting libraries
# we can wrap fftw3 and fftw2 ... but just look for fftw3, since we can do
@@ -494,41 +498,42 @@ AC_OUTPUT([
vipsCC-7.19.pc
vips-7.19.spec
Makefile
- include/vips/version.h
- include/Makefile
- include/vips/Makefile
- libsrc/Makefile
- libsrc/acquire/Makefile
- libsrc/arithmetic/Makefile
- libsrc/boolean/Makefile
- libsrc/cimg/Makefile
- libsrc/colour/Makefile
- libsrc/conversion/Makefile
- libsrc/convolution/Makefile
- libsrc/format/Makefile
- libsrc/freq_filt/Makefile
- libsrc/histograms_lut/Makefile
- libsrc/inplace/Makefile
- libsrc/iofuncs/Makefile
- libsrc/matrix/Makefile
- libsrc/morphology/Makefile
- libsrc/mosaicing/Makefile
- libsrc/other/Makefile
- libsrc/relational/Makefile
- libsrc/resample/Makefile
- libsrc/video/Makefile
- libsrcCC/Makefile
- src/Makefile
- src/iofuncs/Makefile
- src/mosaicing/Makefile
- src/other/Makefile
- src/scripts/Makefile
- src/scripts/batch_crop
- src/scripts/batch_image_convert
- src/scripts/batch_rubber_sheet
- src/scripts/light_correct
- src/scripts/shrink_width
- man/Makefile
+ libvips/include/vips/version.h
+ libvips/include/Makefile
+ libvips/include/vips/Makefile
+ libvips/Makefile
+ libvips/acquire/Makefile
+ libvips/arithmetic/Makefile
+ libvips/boolean/Makefile
+ libvips/cimg/Makefile
+ libvips/colour/Makefile
+ libvips/conversion/Makefile
+ libvips/convolution/Makefile
+ libvips/format/Makefile
+ libvips/freq_filt/Makefile
+ libvips/histograms_lut/Makefile
+ libvips/inplace/Makefile
+ libvips/iofuncs/Makefile
+ libvips/matrix/Makefile
+ libvips/morphology/Makefile
+ libvips/mosaicing/Makefile
+ libvips/other/Makefile
+ libvips/relational/Makefile
+ libvips/resample/Makefile
+ libvips/video/Makefile
+ libvipsCC/include/Makefile
+ libvipsCC/include/vipsCC/Makefile
+ libvipsCC/Makefile
+ tools/Makefile
+ tools/iofuncs/Makefile
+ tools/mosaicing/Makefile
+ tools/other/Makefile
+ tools/scripts/Makefile
+ tools/scripts/batch_crop
+ tools/scripts/batch_image_convert
+ tools/scripts/batch_rubber_sheet
+ tools/scripts/light_correct
+ tools/scripts/shrink_width
contrib/Makefile
contrib/vips2dj/Makefile
contrib/vips2dj/share/Makefile
@@ -538,8 +543,12 @@ AC_OUTPUT([
contrib/vips2dj/share/vips2dj/mono/Makefile
contrib/vdump/Makefile
contrib/mitsub/Makefile
- python/Makefile
- python/vipsCC/Makefile
+ swig/Makefile
+ swig/vipsCC/Makefile
+ man/Makefile
+ doc/Makefile
+ doc/reference/Makefile
+ doc/reference/VIPS-docs.sgml
po/Makefile.in
])
@@ -549,6 +558,7 @@ native win32: $vips_os_win32
open files in binary mode: $vips_binary_open
evaluate with threads: $enable_threads
make symlinks for commands in bin: $enable_links
+build docs with gtkdoc $enable_gtk_doc
* optional packages and modules
use fftw3 for FFT: $with_fftw3
diff --git a/contrib/mitsub/Makefile.am b/contrib/mitsub/Makefile.am
index 79ccae56..624727ea 100644
--- a/contrib/mitsub/Makefile.am
+++ b/contrib/mitsub/Makefile.am
@@ -2,6 +2,6 @@ bin_PROGRAMS = mitsub
mitsub_SOURCES = mitsub.c
-INCLUDES = -I${top_srcdir}/include @VIPS_CFLAGS@ @VIPS_INCLUDES@
+INCLUDES = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@
AM_LDFLAGS = @LDFLAGS@
-LDADD = @VIPS_CFLAGS@ ${top_builddir}/libsrc/libvips.la @VIPS_LIBS@
+LDADD = @VIPS_CFLAGS@ ${top_builddir}/libvips/libvips.la @VIPS_LIBS@
diff --git a/contrib/vdump/Makefile.am b/contrib/vdump/Makefile.am
index 49113dd0..392477b0 100644
--- a/contrib/vdump/Makefile.am
+++ b/contrib/vdump/Makefile.am
@@ -8,8 +8,8 @@ man_MANS = \
pkgdata_DATA = \
vdump.pro
-INCLUDES = -I${top_srcdir}/include @VIPS_CFLAGS@ @VIPS_INCLUDES@
+INCLUDES = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@
AM_LDFLAGS = @LDFLAGS@
-LDADD = @VIPS_CFLAGS@ ${top_builddir}/libsrc/libvips.la @VIPS_LIBS@
+LDADD = @VIPS_CFLAGS@ ${top_builddir}/libvips/libvips.la @VIPS_LIBS@
EXTRA_DIST = $(pkgdata_DATA) $(man_MANS)
diff --git a/contrib/vips2dj/Makefile.am b/contrib/vips2dj/Makefile.am
index 7c982e3c..81a4307a 100644
--- a/contrib/vips2dj/Makefile.am
+++ b/contrib/vips2dj/Makefile.am
@@ -9,9 +9,9 @@ vips2dj_SOURCES = \
vips2ah.c \
vips2dj.c
-INCLUDES = -I${top_srcdir}/include @VIPS_CFLAGS@ @VIPS_INCLUDES@
+INCLUDES = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@
AM_LDFLAGS = @LDFLAGS@
-LDADD = @VIPS_CFLAGS@ ${top_builddir}/libsrc/libvips.la @VIPS_LIBS@
+LDADD = @VIPS_CFLAGS@ ${top_builddir}/libvips/libvips.la @VIPS_LIBS@
EXTRA_DIST = ${vips2dj_DEPENDENCIES}
diff --git a/doc/Makefile b/doc/Makefile
deleted file mode 100644
index c2f953ee..00000000
--- a/doc/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-
-prefix = /home/john/vips
-
-install all:
- cd src; $(MAKE) -f Makefile install
- echo "Making html man pages"
- ./Makehtmlman $(prefix)/share/man/man1
- ./Makehtmlman $(prefix)/share/man/man3
-
-.PHONEY: clean
-clean:
- cd src; $(MAKE) -f Makefile clean
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 00000000..bb4cabcc
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,10 @@
+
+SUBDIRS = reference
+
+EXTRA_DIST = \
+ html \
+ pdf \
+ src \
+ makefile.tex \
+ Makehtmlman \
+ README
diff --git a/doc/README b/doc/README
index 9054eb38..7adb4c11 100644
--- a/doc/README
+++ b/doc/README
@@ -1,6 +1,6 @@
VIPS documentation
-edit Makefile and change "prefix" to be your install prefix (eg.
+edit makefile.tex and change "prefix" to be your install prefix (eg.
"/usr/local/vips-7.8") ... the HTML man page maker will pull manual pages from
this area
diff --git a/doc/reference/Makefile.am b/doc/reference/Makefile.am
new file mode 100644
index 00000000..83dc8192
--- /dev/null
+++ b/doc/reference/Makefile.am
@@ -0,0 +1,101 @@
+## Process this file with automake to produce Makefile.in
+
+# We require automake 1.6 at least.
+AUTOMAKE_OPTIONS = 1.6
+
+# This is a blank Makefile.am for using gtk-doc.
+# Copy this to your project's API docs directory and modify the variables to
+# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples
+# of using the various options.
+
+# The name of the module, e.g. 'glib'.
+DOC_MODULE=VIPS
+
+# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
+DOC_MODULE_VERSION=7
+
+# The top-level SGML file. You can change this if you want to.
+DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
+
+# The directory containing the source code. Relative to $(srcdir).
+# gtk-doc will search all .c & .h files beneath here for inline comments
+# documenting the functions and macros.
+# e.g. DOC_SOURCE_DIR=../../../gtk
+DOC_SOURCE_DIR=$(top_srcdir)/libvips
+
+# Extra options to pass to gtkdoc-scangobj. Not normally needed.
+SCANGOBJ_OPTIONS=
+
+# Extra options to supply to gtkdoc-scan.
+# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
+SCAN_OPTIONS=--rebuild-types
+
+# Extra options to supply to gtkdoc-mkdb.
+# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml
+MKDB_OPTIONS=--sgml-mode --output-format=xml
+
+# Extra options to supply to gtkdoc-mktmpl
+# e.g. MKTMPL_OPTIONS=--only-section-tmpl
+MKTMPL_OPTIONS=
+
+# Extra options to supply to gtkdoc-mkhtml
+MKHTML_OPTIONS=
+
+# Extra options to supply to gtkdoc-fixref. Not normally needed.
+# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html
+FIXXREF_OPTIONS=
+
+# Used for dependencies. The docs will be rebuilt if any of these change.
+# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h
+# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c
+HFILE_GLOB=$(top_srcdir)/libvips/include/vips/*.h
+CFILE_GLOB=$(top_srcdir)/libvips/*/*.c
+
+# Extra header to include when scanning, which are not under DOC_SOURCE_DIR
+# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h
+EXTRA_HFILES=
+
+# Header files to ignore when scanning. Use base file name, no paths
+# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
+IGNORE_HFILES=merge.h debug.h internal.h intl.h CImg.h im_video_v4l1.h global_balance.h dbh.h base64.h templates.h mosaic.h deprecated.h thread.h private.h internal.h almostdeprecated.h fmask.h inlines.h r_access.h struct.h
+
+# Images to copy into HTML directory.
+# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
+HTML_IMAGES=
+
+# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
+# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
+content_files=
+
+# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
+# These files must be listed here *and* in content_files
+# e.g. expand_content_files=running.sgml
+expand_content_files=
+
+# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
+# Only needed if you are using gtkdoc-scangobj to dynamically query widget
+# signals and properties.
+# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
+# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
+# (use VIPS_CFLAGS/VIPS_LIBS/VIPS_LIBS so we pick up the glib-object.h that
+# the scanner uses)
+GTKDOC_CFLAGS = @VIPS_CFLAGS@ @VIPS_INCLUDES@
+GTKDOC_LIBS = @VIPS_CFLAGS@ ${top_builddir}/libvips/libvips.la @VIPS_LIBS@
+
+# This includes the standard gtk-doc make rules, copied by gtkdocize.
+include $(top_srcdir)/gtk-doc.make
+
+# Other files to distribute
+# e.g. EXTRA_DIST += version.xml.in
+#EXTRA_DIST +=
+
+# Files not to distribute
+# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
+# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
+DISTCLEANFILES = VIPS.types
+
+# Comment this out if you want your docs-status tested during 'make check'
+if ENABLE_GTK_DOC
+#TESTS_ENVIRONMENT = cd $(srcsrc)
+#TESTS = $(GTKDOC_CHECK)
+endif
diff --git a/doc/reference/VIPS-docs.sgml b/doc/reference/VIPS-docs.sgml
new file mode 100644
index 00000000..befddfbe
--- /dev/null
+++ b/doc/reference/VIPS-docs.sgml
@@ -0,0 +1,50 @@
+
+
+]>
+
+
+ VIPS Reference Manual
+
+ for VIPS 7.19.0
+ The latest version of this documentation can be found on-line at
+ http://www.vips.ecs.soton.ac.uk/index.php?title=Documentation .
+
+
+
+
+ API by section
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Object Hierarchy
+
+
+
+ API Index
+
+
+
+
+
diff --git a/doc/reference/VIPS-docs.sgml.in b/doc/reference/VIPS-docs.sgml.in
new file mode 100644
index 00000000..9906a391
--- /dev/null
+++ b/doc/reference/VIPS-docs.sgml.in
@@ -0,0 +1,50 @@
+
+
+]>
+
+
+ VIPS Reference Manual
+
+ for VIPS @IM_VERSION@
+ The latest version of this documentation can be found on-line at
+ http://www.vips.ecs.soton.ac.uk/index.php?title=Documentation .
+
+
+
+
+ API by section
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Object Hierarchy
+
+
+
+ API Index
+
+
+
+
+
diff --git a/gtk-doc.make b/gtk-doc.make
new file mode 100644
index 00000000..ed29f94d
--- /dev/null
+++ b/gtk-doc.make
@@ -0,0 +1,177 @@
+# -*- mode: makefile -*-
+
+####################################
+# Everything below here is generic #
+####################################
+
+if GTK_DOC_USE_LIBTOOL
+GTKDOC_CC = $(LIBTOOL) --mode=compile $(CC) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+GTKDOC_LD = $(LIBTOOL) --mode=link $(CC) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS)
+GTKDOC_RUN = $(LIBTOOL) --mode=execute
+else
+GTKDOC_CC = $(CC) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+GTKDOC_LD = $(CC) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS)
+GTKDOC_RUN = sh -c
+endif
+
+# We set GPATH here; this gives us semantics for GNU make
+# which are more like other make's VPATH, when it comes to
+# whether a source that is a target of one rule is then
+# searched for in VPATH/GPATH.
+#
+GPATH = $(srcdir)
+
+TARGET_DIR=$(HTML_DIR)/$(DOC_MODULE)
+
+EXTRA_DIST = \
+ $(content_files) \
+ $(HTML_IMAGES) \
+ $(DOC_MAIN_SGML_FILE) \
+ $(DOC_MODULE)-sections.txt \
+ $(DOC_MODULE)-overrides.txt
+
+DOC_STAMPS=scan-build.stamp sgml-build.stamp html-build.stamp \
+ $(srcdir)/sgml.stamp $(srcdir)/html.stamp
+
+SCANOBJ_FILES = \
+ $(DOC_MODULE).args \
+ $(DOC_MODULE).hierarchy \
+ $(DOC_MODULE).interfaces \
+ $(DOC_MODULE).prerequisites \
+ $(DOC_MODULE).signals
+
+REPORT_FILES = \
+ $(DOC_MODULE)-undocumented.txt \
+ $(DOC_MODULE)-undeclared.txt \
+ $(DOC_MODULE)-unused.txt
+
+CLEANFILES = $(SCANOBJ_FILES) $(REPORT_FILES) $(DOC_STAMPS)
+
+if ENABLE_GTK_DOC
+all-local: html-build.stamp
+else
+all-local:
+endif
+
+docs: html-build.stamp
+
+$(REPORT_FILES): sgml-build.stamp
+
+#### scan ####
+
+scan-build.stamp: $(HFILE_GLOB) $(CFILE_GLOB)
+ @echo 'gtk-doc: Scanning header files'
+ @-chmod -R u+w $(srcdir)
+ cd $(srcdir) && \
+ gtkdoc-scan --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --ignore-headers="$(IGNORE_HFILES)" $(SCAN_OPTIONS) $(EXTRA_HFILES)
+ if grep -l '^..*$$' $(srcdir)/$(DOC_MODULE).types > /dev/null 2>&1 ; then \
+ CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" RUN="$(GTKDOC_RUN)" CFLAGS="$(GTKDOC_CFLAGS) $(CFLAGS)" LDFLAGS="$(GTKDOC_LIBS) $(LDFLAGS)" gtkdoc-scangobj $(SCANGOBJ_OPTIONS) --module=$(DOC_MODULE) --output-dir=$(srcdir) ; \
+ else \
+ cd $(srcdir) ; \
+ for i in $(SCANOBJ_FILES) ; do \
+ test -f $$i || touch $$i ; \
+ done \
+ fi
+ touch scan-build.stamp
+
+$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt: scan-build.stamp
+ @true
+
+#### xml ####
+
+sgml-build.stamp: $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt $(expand_content_files)
+ @echo 'gtk-doc: Building XML'
+ @-chmod -R u+w $(srcdir)
+ cd $(srcdir) && \
+ gtkdoc-mkdb --module=$(DOC_MODULE) --source-dir=$(DOC_SOURCE_DIR) --output-format=xml --expand-content-files="$(expand_content_files)" --main-sgml-file=$(DOC_MAIN_SGML_FILE) $(MKDB_OPTIONS)
+ touch sgml-build.stamp
+
+sgml.stamp: sgml-build.stamp
+ @true
+
+#### html ####
+
+html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files)
+ @echo 'gtk-doc: Building HTML'
+ @-chmod -R u+w $(srcdir)
+ rm -rf $(srcdir)/html
+ mkdir $(srcdir)/html
+ mkhtml_options=""; \
+ gtkdoc-mkhtml 2>&1 --help | grep >/dev/null "\-\-path"; \
+ if test "$(?)" = "0"; then \
+ mkhtml_options=--path="$(srcdir)"; \
+ fi
+ cd $(srcdir)/html && gtkdoc-mkhtml $(mkhtml_options) $(MKHTML_OPTIONS) $(DOC_MODULE) ../$(DOC_MAIN_SGML_FILE)
+ test "x$(HTML_IMAGES)" = "x" || ( cd $(srcdir) && cp $(HTML_IMAGES) html )
+ @echo 'gtk-doc: Fixing cross-references'
+ cd $(srcdir) && gtkdoc-fixxref --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS)
+ touch html-build.stamp
+
+##############
+
+clean-local:
+ rm -f *~ *.bak
+ rm -rf .libs
+
+distclean-local:
+ cd $(srcdir) && \
+ rm -rf xml $(REPORT_FILES) \
+ $(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt
+
+maintainer-clean-local: clean
+ cd $(srcdir) && rm -rf html
+
+install-data-local:
+ installfiles=`echo $(srcdir)/html/*`; \
+ if test "$$installfiles" = '$(srcdir)/html/*'; \
+ then echo '-- Nothing to install' ; \
+ else \
+ if test -n "$(DOC_MODULE_VERSION)"; then \
+ installdir="$(DESTDIR)$(TARGET_DIR)-$(DOC_MODULE_VERSION)"; \
+ else \
+ installdir="$(DESTDIR)$(TARGET_DIR)"; \
+ fi; \
+ $(mkinstalldirs) $${installdir} ; \
+ for i in $$installfiles; do \
+ echo '-- Installing '$$i ; \
+ $(INSTALL_DATA) $$i $${installdir}; \
+ done; \
+ if test -n "$(DOC_MODULE_VERSION)"; then \
+ mv -f $${installdir}/$(DOC_MODULE).devhelp2 \
+ $${installdir}/$(DOC_MODULE)-$(DOC_MODULE_VERSION).devhelp2; \
+ mv -f $${installdir}/$(DOC_MODULE).devhelp \
+ $${installdir}/$(DOC_MODULE)-$(DOC_MODULE_VERSION).devhelp; \
+ fi; \
+ ! which gtkdoc-rebase >/dev/null 2>&1 || \
+ gtkdoc-rebase --relative --dest-dir=$(DESTDIR) --html-dir=$${installdir} ; \
+ fi
+
+uninstall-local:
+ if test -n "$(DOC_MODULE_VERSION)"; then \
+ installdir="$(DESTDIR)$(TARGET_DIR)-$(DOC_MODULE_VERSION)"; \
+ else \
+ installdir="$(DESTDIR)$(TARGET_DIR)"; \
+ fi; \
+ rm -rf $${installdir}
+
+#
+# Require gtk-doc when making dist
+#
+if ENABLE_GTK_DOC
+dist-check-gtkdoc:
+else
+dist-check-gtkdoc:
+ @echo "*** gtk-doc must be installed and enabled in order to make dist"
+ @false
+endif
+
+dist-hook: dist-check-gtkdoc dist-hook-local
+ mkdir $(distdir)/html
+ cp $(srcdir)/html/* $(distdir)/html
+ -cp $(srcdir)/$(DOC_MODULE).types $(distdir)/
+ -cp $(srcdir)/$(DOC_MODULE)-sections.txt $(distdir)/
+ cd $(distdir) && rm -f $(DISTCLEANFILES)
+ ! which gtkdoc-rebase >/dev/null 2>&1 || \
+ gtkdoc-rebase --online --relative --html-dir=$(distdir)/html
+
+.PHONY : dist-hook-local docs
diff --git a/libvips/Makefile.am b/libvips/Makefile.am
new file mode 100644
index 00000000..42f08c4d
--- /dev/null
+++ b/libvips/Makefile.am
@@ -0,0 +1,67 @@
+# only build in the cimg dir if it's enabled
+if WITH_CIMG
+C_COMPILE_DIR = cimg
+C_DIST_DIR =
+C_LIB = cimg/libcimg.la
+else
+C_COMPILE_DIR =
+C_DIST_DIR = cimg
+C_LIB =
+endif
+
+SUBDIRS = \
+ include \
+ acquire \
+ arithmetic \
+ resample \
+ boolean \
+ colour \
+ conversion \
+ convolution \
+ $(C_COMPILE_DIR) \
+ format \
+ freq_filt \
+ histograms_lut \
+ inplace \
+ iofuncs \
+ matrix \
+ morphology \
+ mosaicing \
+ other \
+ relational \
+ video \
+ .
+
+lib_LTLIBRARIES = libvips.la
+
+libvips_la_SOURCES = dummy.c dummy2.cc
+
+# DLLs need dependant libs there too ... put @VIPS_LIBS@ at the end
+libvips_la_LIBADD = \
+ acquire/libacquire.la \
+ resample/libresample.la \
+ arithmetic/libarithmetic.la \
+ boolean/libboolean.la \
+ colour/libcolour.la \
+ conversion/libconversion.la \
+ convolution/libconvolution.la \
+ $(C_LIB) \
+ format/libformat.la \
+ freq_filt/libfreq_filt.la \
+ histograms_lut/libhistograms_lut.la \
+ inplace/libinplace.la \
+ iofuncs/libiofuncs.la \
+ matrix/libmatrix.la \
+ morphology/libmorphology.la \
+ mosaicing/libmosaicing.la \
+ other/libother.la \
+ relational/librelational.la \
+ video/libvideo.la \
+ @VIPS_LIBS@
+
+libvips_la_LDFLAGS = \
+ -no-undefined \
+ -version-info @LIBRARY_CURRENT@:@LIBRARY_REVISION@:@LIBRARY_AGE@
+
+EXTRA_DIST = \
+ $(C_DIST_DIR)
diff --git a/libvips/acquire/Makefile.am b/libvips/acquire/Makefile.am
new file mode 100644
index 00000000..849f96a3
--- /dev/null
+++ b/libvips/acquire/Makefile.am
@@ -0,0 +1,7 @@
+noinst_LTLIBRARIES = libacquire.la
+
+libacquire_la_SOURCES = \
+ im_clamp.c
+
+INCLUDES = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@
+
diff --git a/libvips/acquire/im_clamp.c b/libvips/acquire/im_clamp.c
new file mode 100644
index 00000000..86df7570
--- /dev/null
+++ b/libvips/acquire/im_clamp.c
@@ -0,0 +1,127 @@
+/* @(#) Function to perform black level correction given black image
+ * @(#) designed for PAD camera single field black to apply in blocks
+ * @(#) as each is reused for higher resolution pels (eg: 6 8 for Progres)
+ * @(#) IM_BANDFMT_UCHAR images only. Always writes UCHAR.
+ * @(#) int im_clamp(in, w, out, hstep, vstep)
+ * @(#) IMAGE *in, *w, *out; int hstep, vstep;
+ * @(#) - Compute clip(image - (black)) ie subtract black no negatives
+ * @(#) scales for low res Progres images to replicate black value
+ * @(#) Returns 0 on success and -1 on error
+ * fiddle at your peril - nasty code
+ * Copyright: 1993 KM
+ * 20/8/93
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+
+#include
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+int
+im_clamp( in, out,black, hstep, vstep )
+IMAGE *in, *black, *out;
+int hstep, vstep;
+{ PEL *p, *blk, *bline, *bexp;
+PEL *q, *outbuf;
+int rep;
+int x, y, bnd;
+int temp, blacky, newblacky;
+
+if( im_iocheck( in, out ) )
+ return( -1 );
+if( in->Bbits != 8 ||
+ in->Coding != IM_CODING_NONE || in->BandFmt != IM_BANDFMT_UCHAR ) {
+ im_error( "im_clamp", "%s", _( "bad input format" ) );
+ return( -1 );
+}
+if( black->Bbits != 8 ||
+ black->Coding != IM_CODING_NONE || black->BandFmt != IM_BANDFMT_UCHAR ) {
+ im_error( "im_clamp", "%s", _( "bad black format" ) );
+ return( -1 );
+}
+
+/* Set up the output header.
+ */
+if( im_cp_desc( out, in ) )
+ return( -1 );
+if( im_setupout( out ) )
+ return( -1 );
+
+/* Make buffer for expanded black line
+ */
+if( !(bline = (PEL *) im_malloc( out, black->Bands * hstep * in->Xsize )) )
+ return( -1 );
+/* Make buffer we write to.
+ */
+if( !(outbuf = (PEL *) im_malloc( out, out->Bands * out->Xsize )) )
+ return( -1 );
+blacky = -1;
+p = (PEL *) in->data;
+
+for( y = 0; y < in->Ysize; y++ ) {
+ /* calc corresponding black line - get new one if different */
+ newblacky = (vstep * black->Ysize - in->Ysize + y)/vstep;
+ if( newblacky != blacky){
+ blacky = newblacky;
+ /* time to expand a new black line */
+ blk = (PEL *) (black->data +
+ black->Xsize * black->Bands * blacky);
+ for(bexp = bline, x = 0; x < black->Xsize; x++){
+ for(rep = 0; rep < hstep; rep++)
+ for(q=blk, bnd = 0; bnd < in->Bands; bnd++)
+ *bexp++ = *q++;
+ blk += black->Bands;
+ }
+ }
+
+ /* correct a line of image */
+ bexp = bline;
+ q = outbuf;
+ for( x = 0; x < (out->Bands * out->Xsize); x++ ) {
+ temp = ((int) *p++ - *bexp++);
+ if( temp < 0 ) temp = 0;
+ *q++ = (PEL)temp;
+ }
+
+ if( im_writeline( y, out, outbuf ) )
+ return( -1 );
+} /* end of a line */
+
+return( 0 );
+}
diff --git a/libvips/arithmetic/Makefile.am b/libvips/arithmetic/Makefile.am
new file mode 100644
index 00000000..8b1d1c98
--- /dev/null
+++ b/libvips/arithmetic/Makefile.am
@@ -0,0 +1,45 @@
+noinst_LTLIBRARIES = libarithmetic.la
+
+libarithmetic_la_SOURCES = \
+ arith_dispatch.c \
+ im_abs.c \
+ im_add.c \
+ im_avg.c \
+ im_point_bilinear.c \
+ im_bandmean.c \
+ im_cmulnorm.c \
+ im_costra.c \
+ im_cross_phase.c \
+ im_deviate.c \
+ im_divide.c \
+ im_ceil.c \
+ im_floor.c \
+ im_expntra.c \
+ im_fav4.c \
+ im_gadd.c \
+ im_gaddim.c \
+ im_gfadd.c \
+ im_invert.c \
+ im_linreg.c \
+ im_lintra.c \
+ im_litecor.c \
+ im_log10tra.c \
+ im_logtra.c \
+ im_max.c \
+ im_maxpos.c \
+ im_maxpos_avg.c \
+ im_maxpos_vec.c \
+ im_measure.c \
+ im_min.c \
+ im_minpos.c \
+ im_multiply.c \
+ im_powtra.c \
+ im_remainder.c \
+ im_rint.c \
+ im_sign.c \
+ im_sintra.c \
+ im_stats.c \
+ im_subtract.c \
+ im_tantra.c
+
+INCLUDES = -I${top_srcdir}/libvips/include @VIPS_CFLAGS@ @VIPS_INCLUDES@
diff --git a/libvips/arithmetic/arith_dispatch.c b/libvips/arithmetic/arith_dispatch.c
new file mode 100644
index 00000000..b5ad1657
--- /dev/null
+++ b/libvips/arithmetic/arith_dispatch.c
@@ -0,0 +1,1539 @@
+/* Function dispatch tables for arithmetic.
+ *
+ * J. Cupitt, 8/4/93.
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/**
+ * SECTION: arithmetic
+ * @short_description: operations which perform pixel arithmetic
+ *
+ * @see_also: iofuncs
+ * @stability: Stable
+ * @include: vips/vips.h
+ *
+ * These operations perform pixel arithmetic, that is, they perform an
+ * arithmetic operation, such as addition, on every pixel in an image or a
+ * pair of images. All (except in a few cases noted below) will work with
+ * images of any type (or any mixture of types), of any size and of any number
+ * of bands.
+ *
+ * For binary operations, if the number of bands differs, one of the images
+ * must have one band. So you can add a 1 band image to a 3 band image, for
+ * example, and the 1 band image will be added 3 times, but you can't add a
+ * 2 band image to a 3 band image.
+ *
+ * Arithmetic operations try to preserve precision by increasing the number of
+ * bits in the output image when necessary. Generally, this follows the ANSI C
+ * conventions for type promotion, so multiplying two
+ * %IM_BANDFMT_UCHAR images together, for example, produces a
+ * %IM_BANDFMT_USHORT image, and taking the im_costra() of a
+ * %IM_BANDFMT_USHORT image produces %IM_BANDFMT_FLOAT image.
+ *
+ * For binary arithmetic operations, type promotion occurs in two stages.
+ * First, the two input images are cast up to the smallest common format,
+ * that is, the type with the smallest range that can represent the full
+ * range of both inputs. This conversion can be represented as a table:
+ *
+ *
+ * Smallest common format
+ *
+ *
+ *
+ * @in2/@in1
+ * uchar
+ * char
+ * ushort
+ * short
+ * uint
+ * int
+ * float
+ * double
+ * complex
+ * double complex
+ *
+ *
+ *
+ *
+ * uchar
+ * ushort
+ * short
+ * ushort
+ * short
+ * uint
+ * int
+ * float
+ * double
+ * complex
+ * double complex
+ *
+ *
+ * char
+ * short
+ * short
+ * short
+ * short
+ * int
+ * int
+ * float
+ * double
+ * complex
+ * double complex
+ *
+ *
+ * ushort
+ * ushort
+ * short
+ * ushort
+ * short
+ * uint
+ * int
+ * float
+ * double
+ * complex
+ * double complex
+ *
+ *
+ * short
+ * short
+ * short
+ * short
+ * short
+ * int
+ * int
+ * float
+ * double
+ * complex
+ * double complex
+ *
+ *
+ * uint
+ * uint
+ * int
+ * uint
+ * int
+ * uint
+ * int
+ * float
+ * double
+ * complex
+ * double complex
+ *
+ *
+ * int
+ * int
+ * int
+ * int
+ * int
+ * int
+ * int
+ * float
+ * double
+ * complex
+ * double complex
+ *
+ *
+ * float
+ * float
+ * float
+ * float
+ * float
+ * float
+ * float
+ * float
+ * double
+ * complex
+ * double complex
+ *
+ *
+ * double
+ * double
+ * double
+ * double
+ * double
+ * double
+ * double
+ * double
+ * double
+ * double complex
+ * double complex
+ *
+ *
+ * complex
+ * complex
+ * complex
+ * complex
+ * complex
+ * complex
+ * complex
+ * complex
+ * double complex
+ * complex
+ * double complex
+ *
+ *
+ * double complex
+ * double complex
+ * double complex
+ * double complex
+ * double complex
+ * double complex
+ * double complex
+ * double complex
+ * double complex
+ * double complex
+ * double complex
+ *
+ *
+ *
+ *
+ *
+ * In the second stage, the operation is performed between the two identical
+ * types to form the output. The details vary between operations, but
+ * generally the principle is that the output type should be large enough to
+ * represent the whole rage of possible values, except that int never becomes
+ * float.
+ */
+
+/* One image in, one out.
+ */
+static im_arg_desc one_in_one_out[] = {
+ IM_INPUT_IMAGE( "in" ),
+ IM_OUTPUT_IMAGE( "out" )
+};
+
+/* Two images in, one out.
+ */
+static im_arg_desc two_in_one_out[] = {
+ IM_INPUT_IMAGE( "in1" ),
+ IM_INPUT_IMAGE( "in2" ),
+ IM_OUTPUT_IMAGE( "out" )
+};
+
+/* Image in, number out.
+ */
+static im_arg_desc image_in_num_out[] = {
+ IM_INPUT_IMAGE( "in" ),
+ IM_OUTPUT_DOUBLE( "value" )
+};
+
+/* Call im_abs via arg vector.
+ */
+static int
+abs_vec( im_object *argv )
+{
+ return( im_abs( argv[0], argv[1] ) );
+}
+
+/* Description of im_abs.
+ */
+static im_function abs_desc = {
+ "im_abs", /* Name */
+ N_( "absolute value" ), /* Description */
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ abs_vec, /* Dispatch function */
+ IM_NUMBER( one_in_one_out ), /* Size of arg list */
+ one_in_one_out /* Arg list */
+};
+
+/* Call im_add via arg vector.
+ */
+static int
+add_vec( im_object *argv )
+{
+ return( im_add( argv[0], argv[1], argv[2] ) );
+}
+
+/* Description of im_add.
+ */
+static im_function add_desc = {
+ "im_add", /* Name */
+ N_( "add two images" ), /* Description */
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ add_vec, /* Dispatch function */
+ IM_NUMBER( two_in_one_out ), /* Size of arg list */
+ two_in_one_out /* Arg list */
+};
+
+/* Call im_avg via arg vector.
+ */
+static int
+avg_vec( im_object *argv )
+{
+ double f;
+
+ if( im_avg( argv[0], &f ) )
+ return( -1 );
+
+ *((double *) argv[1]) = f;
+ return( 0 );
+}
+
+/* Description of im_avg.
+ */
+static im_function avg_desc = {
+ "im_avg", /* Name */
+ N_( "average value of image" ), /* Description */
+ IM_FN_PIO, /* Flags */
+ avg_vec, /* Dispatch function */
+ IM_NUMBER( image_in_num_out ), /* Size of arg list */
+ image_in_num_out /* Arg list */
+};
+
+/* Args to im_point_bilinear.
+ */
+static im_arg_desc point_bilinear_args[] = {
+ IM_INPUT_IMAGE ("in"),
+ IM_INPUT_DOUBLE("x"),
+ IM_INPUT_DOUBLE("y"),
+ IM_INPUT_INT("band"),
+ IM_OUTPUT_DOUBLE("val")
+};
+
+/* Call im_point_bilinear via arg vector.
+ */
+static int
+point_bilinear_vec( im_object *argv )
+{
+ return im_point_bilinear( argv[0], *(double*)argv[1], *(double*)argv[2], *(int*)argv[3], argv[4] );
+}
+
+/* Description of im_point_bilinear.
+ */
+static im_function point_bilinear_desc = {
+ "im_point_bilinear",
+ "interpolate value at single point, linearly",
+ IM_FN_PIO,
+ point_bilinear_vec,
+ IM_NUMBER( point_bilinear_args ),
+ point_bilinear_args
+};
+
+/* Call im_cmulnorm via arg vector.
+ */
+static int
+cmulnorm_vec( im_object *argv )
+{
+ return( im_cmulnorm( argv[0], argv[1], argv[2] ) );
+}
+
+/* Description of im_cmulnorm.
+ */
+static im_function cmulnorm_desc = {
+ "im_cmulnorm", /* Name */
+ N_( "multiply two complex images, normalising output" ),
+ IM_FN_PIO, /* Flags */
+ cmulnorm_vec, /* Dispatch function */
+ IM_NUMBER( two_in_one_out ), /* Size of arg list */
+ two_in_one_out /* Arg list */
+};
+
+/* Call im_deviate via arg vector.
+ */
+static int
+deviate_vec( im_object *argv )
+{
+ double f;
+
+ if( im_deviate( argv[0], &f ) )
+ return( -1 );
+
+ *((double *) argv[1]) = f;
+ return( 0 );
+}
+
+/* Description of im_deviate.
+ */
+static im_function deviate_desc = {
+ "im_deviate", /* Name */
+ N_( "standard deviation of image" ), /* Description */
+ IM_FN_PIO, /* Flags */
+ deviate_vec, /* Dispatch function */
+ IM_NUMBER( image_in_num_out ), /* Size of arg list */
+ image_in_num_out /* Arg list */
+};
+
+/* Call im_exp10tra via arg vector.
+ */
+static int
+exp10tra_vec( im_object *argv )
+{
+ return( im_exp10tra( argv[0], argv[1] ) );
+}
+
+/* Description of im_exp10tra.
+ */
+static im_function exp10tra_desc = {
+ "im_exp10tra", /* Name */
+ N_( "10^pel of image" ), /* Description */
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ exp10tra_vec, /* Dispatch function */
+ IM_NUMBER( one_in_one_out ), /* Size of arg list */
+ one_in_one_out /* Arg list */
+};
+
+/* Call im_exptra via arg vector.
+ */
+static int
+exptra_vec( im_object *argv )
+{
+ return( im_exptra( argv[0], argv[1] ) );
+}
+
+/* Description of im_exptra.
+ */
+static im_function exptra_desc = {
+ "im_exptra", /* Name */
+ N_( "e^pel of image" ), /* Description */
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ exptra_vec, /* Dispatch function */
+ IM_NUMBER( one_in_one_out ), /* Size of arg list */
+ one_in_one_out /* Arg list */
+};
+
+/* Args for im_powtra().
+ */
+static im_arg_desc powtra_args[] = {
+ IM_INPUT_IMAGE( "in" ),
+ IM_OUTPUT_IMAGE( "out" ),
+ IM_INPUT_DOUBLE( "x" )
+};
+
+/* Call im_expntra via arg vector.
+ */
+static int
+expntra_vec( im_object *argv )
+{
+ double a = *((double *) argv[2]);
+
+ return( im_expntra( argv[0], argv[1], a ) );
+}
+
+/* Description of im_expntra.
+ */
+static im_function expntra_desc = {
+ "im_expntra", /* Name */
+ N_( "x^pel of image" ), /* Description */
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ expntra_vec, /* Dispatch function */
+ IM_NUMBER( powtra_args ), /* Size of arg list */
+ powtra_args /* Arg list */
+};
+
+/* Args for im_expntra_vec().
+ */
+static im_arg_desc expntra_vec_args[] = {
+ IM_INPUT_IMAGE( "in" ),
+ IM_OUTPUT_IMAGE( "out" ),
+ IM_INPUT_DOUBLEVEC( "v" )
+};
+
+/* Call im_expntra_vec() via arg vector.
+ */
+static int
+expntra_vec_vec( im_object *argv )
+{
+ im_doublevec_object *rv = (im_doublevec_object *) argv[2];
+
+ return( im_expntra_vec( argv[0], argv[1], rv->n, rv->vec ) );
+}
+
+/* Description of im_expntra_vec.
+ */
+static im_function expntra_vec_desc = {
+ "im_expntra_vec", /* Name */
+ N_( "[x,y,z]^pel of image" ), /* Description */
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ expntra_vec_vec, /* Dispatch function */
+ IM_NUMBER( expntra_vec_args ), /* Size of arg list */
+ expntra_vec_args /* Arg list */
+};
+
+/* Four images in, one out.
+ */
+static im_arg_desc fav4_args[] = {
+ IM_INPUT_IMAGE( "in1" ),
+ IM_INPUT_IMAGE( "in2" ),
+ IM_INPUT_IMAGE( "in3" ),
+ IM_INPUT_IMAGE( "in4" ),
+ IM_OUTPUT_IMAGE( "out" )
+};
+
+/* Call im_fav4 via arg vector.
+ */
+static int
+fav4_vec( im_object *argv )
+{
+ IMAGE *buf[4];
+
+ buf[0] = argv[0];
+ buf[1] = argv[1];
+ buf[2] = argv[2];
+ buf[3] = argv[3];
+
+ return( im_fav4( &buf[0], argv[4] ) );
+}
+
+/* Description of im_fav4.
+ */
+static im_function fav4_desc = {
+ "im_fav4", /* Name */
+ N_( "average of 4 images" ),
+ 0, /* Flags */
+ fav4_vec, /* Dispatch function */
+ IM_NUMBER( fav4_args ), /* Size of arg list */
+ fav4_args /* Arg list */
+};
+
+/* Call im_divide via arg vector.
+ */
+static int
+divide_vec( im_object *argv )
+{
+ return( im_divide( argv[0], argv[1], argv[2] ) );
+}
+
+/* Description of im_divide.
+ */
+static im_function divide_desc = {
+ "im_divide", /* Name */
+ N_( "divide two images" ),
+ IM_FN_PIO, /* Flags */
+ divide_vec, /* Dispatch function */
+ IM_NUMBER( two_in_one_out ), /* Size of arg list */
+ two_in_one_out /* Arg list */
+};
+
+/* Args for im_gadd().
+ */
+static im_arg_desc gadd_args[] = {
+ IM_INPUT_DOUBLE( "a" ),
+ IM_INPUT_IMAGE( "in1" ),
+ IM_INPUT_DOUBLE( "b" ),
+ IM_INPUT_IMAGE( "in2" ),
+ IM_INPUT_DOUBLE( "c" ),
+ IM_OUTPUT_IMAGE( "out" )
+};
+
+/* Call im_gadd() via arg vector.
+ */
+static int
+gadd_vec( im_object *argv )
+{
+ double a = *((double *) argv[0]);
+ double b = *((double *) argv[2]);
+ double c = *((double *) argv[4]);
+
+ return( im_gadd( a, argv[1], b, argv[3], c, argv[5] ) );
+}
+
+/* Description of im_gadd().
+ */
+static im_function gadd_desc = {
+ "im_gadd", /* Name */
+ N_( "calculate a*in1 + b*in2 + c = outfile" ),
+ 0, /* Flags */
+ gadd_vec, /* Dispatch function */
+ IM_NUMBER( gadd_args ), /* Size of arg list */
+ gadd_args /* Arg list */
+};
+
+/* Call im_invert via arg vector.
+ */
+static int
+invert_vec( im_object *argv )
+{
+ return( im_invert( argv[0], argv[1] ) );
+}
+
+/* Description of im_invert.
+ */
+static im_function invert_desc = {
+ "im_invert", /* Name */
+ N_( "photographic negative" ), /* Description */
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ invert_vec, /* Dispatch function */
+ IM_NUMBER( one_in_one_out ), /* Size of arg list */
+ one_in_one_out /* Arg list */
+};
+
+/* Args for im_lintra().
+ */
+static im_arg_desc lintra_args[] = {
+ IM_INPUT_DOUBLE( "a" ),
+ IM_INPUT_IMAGE( "in" ),
+ IM_INPUT_DOUBLE( "b" ),
+ IM_OUTPUT_IMAGE( "out" )
+};
+
+/* Call im_lintra() via arg vector.
+ */
+static int
+lintra_vec( im_object *argv )
+{
+ double a = *((double *) argv[0]);
+ double b = *((double *) argv[2]);
+
+ return( im_lintra( a, argv[1], b, argv[3] ) );
+}
+
+/* Description of im_lintra().
+ */
+static im_function lintra_desc = {
+ "im_lintra", /* Name */
+ N_( "calculate a*in + b = outfile" ),
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ lintra_vec, /* Dispatch function */
+ IM_NUMBER( lintra_args ), /* Size of arg list */
+ lintra_args /* Arg list */
+};
+
+/* Args for im_lintra_vec().
+ */
+static im_arg_desc lintra_vec_args[] = {
+ IM_INPUT_DOUBLEVEC( "a" ),
+ IM_INPUT_IMAGE( "in" ),
+ IM_INPUT_DOUBLEVEC( "b" ),
+ IM_OUTPUT_IMAGE( "out" )
+};
+
+/* Call im_lintra_vec() via arg vector.
+ */
+static int
+lintra_vec_vec( im_object *argv )
+{
+ im_doublevec_object *dva = (im_doublevec_object *) argv[0];
+ im_doublevec_object *dvb = (im_doublevec_object *) argv[2];
+
+ if( dva->n != dvb->n ) {
+ im_error( "im_lintra_vec",
+ "%s", _( "vectors not equal length" ) );
+ return( -1 );
+ }
+
+ return( im_lintra_vec( dva->n, dva->vec, argv[1], dvb->vec, argv[3] ) );
+}
+
+/* Description of im_lintra_vec().
+ */
+static im_function lintra_vec_desc = {
+ "im_lintra_vec", /* Name */
+ N_( "calculate a*in + b -> out, a and b vectors" ),
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ lintra_vec_vec, /* Dispatch function */
+ IM_NUMBER( lintra_vec_args ), /* Size of arg list */
+ lintra_vec_args /* Arg list */
+};
+
+/* Args for im_litecor().
+ */
+static im_arg_desc litecor_args[] = {
+ IM_INPUT_IMAGE( "in" ),
+ IM_INPUT_IMAGE( "white" ),
+ IM_OUTPUT_IMAGE( "out" ),
+ IM_INPUT_INT( "clip" ),
+ IM_INPUT_DOUBLE( "factor" )
+};
+
+/* Call im_litecor() via arg vector.
+ */
+static int
+litecor_vec( im_object *argv )
+{
+ int clip = *((int *) argv[3]);
+ double factor = *((double *) argv[4]);
+
+ return( im_litecor( argv[0], argv[1], argv[2], clip, factor ) );
+}
+
+/* Description of im_litecor().
+ */
+static im_function litecor_desc = {
+ "im_litecor", /* Name */
+ N_( "calculate max(white)*factor*(in/white), if clip == 1" ),
+ 0, /* Flags */
+ litecor_vec, /* Dispatch function */
+ IM_NUMBER( litecor_args ), /* Size of arg list */
+ litecor_args /* Arg list */
+};
+
+/* Call im_log10tra via arg vector.
+ */
+static int
+log10tra_vec( im_object *argv )
+{
+ return( im_log10tra( argv[0], argv[1] ) );
+}
+
+/* Description of im_log10tra.
+ */
+static im_function log10tra_desc = {
+ "im_log10tra", /* Name */
+ N_( "log10 of image" ), /* Description */
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ log10tra_vec, /* Dispatch function */
+ IM_NUMBER( one_in_one_out ), /* Size of arg list */
+ one_in_one_out /* Arg list */
+};
+
+/* Call im_logtra via arg vector.
+ */
+static int
+logtra_vec( im_object *argv )
+{
+ return( im_logtra( argv[0], argv[1] ) );
+}
+
+/* Description of im_logtra.
+ */
+static im_function logtra_desc = {
+ "im_logtra", /* Name */
+ N_( "ln of image" ), /* Description */
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ logtra_vec, /* Dispatch function */
+ IM_NUMBER( one_in_one_out ), /* Size of arg list */
+ one_in_one_out /* Arg list */
+};
+
+/* Call im_tantra via arg vector.
+ */
+static int
+tantra_vec( im_object *argv )
+{
+ return( im_tantra( argv[0], argv[1] ) );
+}
+
+/* Description of im_tantra.
+ */
+static im_function tantra_desc = {
+ "im_tantra", /* Name */
+ N_( "tan of image (angles in degrees)" ),
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ tantra_vec, /* Dispatch function */
+ IM_NUMBER( one_in_one_out ), /* Size of arg list */
+ one_in_one_out /* Arg list */
+};
+
+/* Call im_atantra via arg vector.
+ */
+static int
+atantra_vec( im_object *argv )
+{
+ return( im_atantra( argv[0], argv[1] ) );
+}
+
+/* Description of im_atantra.
+ */
+static im_function atantra_desc = {
+ "im_atantra", /* Name */
+ N_( "atan of image (result in degrees)" ),
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ atantra_vec, /* Dispatch function */
+ IM_NUMBER( one_in_one_out ), /* Size of arg list */
+ one_in_one_out /* Arg list */
+};
+
+/* Call im_costra via arg vector.
+ */
+static int
+costra_vec( im_object *argv )
+{
+ return( im_costra( argv[0], argv[1] ) );
+}
+
+/* Description of im_costra.
+ */
+static im_function costra_desc = {
+ "im_costra", /* Name */
+ N_( "cos of image (angles in degrees)" ),
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ costra_vec, /* Dispatch function */
+ IM_NUMBER( one_in_one_out ), /* Size of arg list */
+ one_in_one_out /* Arg list */
+};
+
+/* Call im_acostra via arg vector.
+ */
+static int
+acostra_vec( im_object *argv )
+{
+ return( im_acostra( argv[0], argv[1] ) );
+}
+
+/* Description of im_acostra.
+ */
+static im_function acostra_desc = {
+ "im_acostra", /* Name */
+ N_( "acos of image (result in degrees)" ),
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ acostra_vec, /* Dispatch function */
+ IM_NUMBER( one_in_one_out ), /* Size of arg list */
+ one_in_one_out /* Arg list */
+};
+
+/* Call im_ceil via arg vector.
+ */
+static int
+ceil_vec( im_object *argv )
+{
+ return( im_ceil( argv[0], argv[1] ) );
+}
+
+/* Description of im_ceil.
+ */
+static im_function ceil_desc = {
+ "im_ceil", /* Name */
+ N_( "round to smallest integal value not less than" ),
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ ceil_vec, /* Dispatch function */
+ IM_NUMBER( one_in_one_out ), /* Size of arg list */
+ one_in_one_out /* Arg list */
+};
+
+/* Call im_floor via arg vector.
+ */
+static int
+floor_vec( im_object *argv )
+{
+ return( im_floor( argv[0], argv[1] ) );
+}
+
+/* Description of im_floor.
+ */
+static im_function floor_desc = {
+ "im_floor", /* Name */
+ N_( "round to largest integal value not greater than" ),
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ floor_vec, /* Dispatch function */
+ IM_NUMBER( one_in_one_out ), /* Size of arg list */
+ one_in_one_out /* Arg list */
+};
+
+/* Call im_rint via arg vector.
+ */
+static int
+rint_vec( im_object *argv )
+{
+ return( im_rint( argv[0], argv[1] ) );
+}
+
+/* Description of im_rint.
+ */
+static im_function rint_desc = {
+ "im_rint", /* Name */
+ N_( "round to nearest integal value" ),
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ rint_vec, /* Dispatch function */
+ IM_NUMBER( one_in_one_out ), /* Size of arg list */
+ one_in_one_out /* Arg list */
+};
+
+/* Call im_sintra via arg vector.
+ */
+static int
+sintra_vec( im_object *argv )
+{
+ return( im_sintra( argv[0], argv[1] ) );
+}
+
+/* Description of im_sintra.
+ */
+static im_function sintra_desc = {
+ "im_sintra", /* Name */
+ N_( "sin of image (angles in degrees)" ),
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ sintra_vec, /* Dispatch function */
+ IM_NUMBER( one_in_one_out ), /* Size of arg list */
+ one_in_one_out /* Arg list */
+};
+
+/* Call im_bandmean via arg vector.
+ */
+static int
+bandmean_vec( im_object *argv )
+{
+ return( im_bandmean( argv[0], argv[1] ) );
+}
+
+/* Description of im_bandmean.
+ */
+static im_function bandmean_desc = {
+ "im_bandmean", /* Name */
+ N_( "average image bands" ),
+ IM_FN_PIO, /* Flags */
+ bandmean_vec, /* Dispatch function */
+ IM_NUMBER( one_in_one_out ), /* Size of arg list */
+ one_in_one_out /* Arg list */
+};
+
+/* Call im_sign via arg vector.
+ */
+static int
+sign_vec( im_object *argv )
+{
+ return( im_sign( argv[0], argv[1] ) );
+}
+
+/* Description of im_sign.
+ */
+static im_function sign_desc = {
+ "im_sign", /* Name */
+ N_( "unit vector in direction of value" ),
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ sign_vec, /* Dispatch function */
+ IM_NUMBER( one_in_one_out ), /* Size of arg list */
+ one_in_one_out /* Arg list */
+};
+
+/* Call im_asintra via arg vector.
+ */
+static int
+asintra_vec( im_object *argv )
+{
+ return( im_asintra( argv[0], argv[1] ) );
+}
+
+/* Description of im_asintra.
+ */
+static im_function asintra_desc = {
+ "im_asintra", /* Name */
+ N_( "asin of image (result in degrees)" ),
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ asintra_vec, /* Dispatch function */
+ IM_NUMBER( one_in_one_out ), /* Size of arg list */
+ one_in_one_out /* Arg list */
+};
+
+/* Call im_max via arg vector.
+ */
+static int
+max_vec( im_object *argv )
+{
+ double f;
+
+ if( im_max( argv[0], &f ) )
+ return( -1 );
+ *((double *) argv[1]) = f;
+
+ return( 0 );
+}
+
+/* Description of im_max.
+ */
+static im_function max_desc = {
+ "im_max", /* Name */
+ N_( "maximum value of image" ), /* Description */
+ IM_FN_PIO, /* Flags */
+ max_vec, /* Dispatch function */
+ IM_NUMBER( image_in_num_out ), /* Size of arg list */
+ image_in_num_out /* Arg list */
+};
+
+/* Args for maxpos (and minpos).
+ */
+static im_arg_desc maxpos_args[] = {
+ IM_INPUT_IMAGE( "in" ),
+ IM_OUTPUT_COMPLEX( "position" )
+};
+
+/* Call im_maxpos via arg vector.
+ */
+static int
+maxpos_vec( im_object *argv )
+{
+ double f;
+ int x, y;
+
+ if( im_maxpos( argv[0], &x, &y, &f ) )
+ return( -1 );
+
+ ((double *) argv[1])[0] = x;
+ ((double *) argv[1])[1] = y;
+
+ return( 0 );
+}
+
+/* Description of im_maxpos.
+ */
+static im_function maxpos_desc = {
+ "im_maxpos", /* Name */
+ N_( "position of maximum value of image" ),
+ 0, /* Flags */
+ maxpos_vec, /* Dispatch function */
+ IM_NUMBER( maxpos_args ), /* Size of arg list */
+ maxpos_args /* Arg list */
+};
+
+/* Args to im_maxpos_avg.
+ */
+static im_arg_desc maxpos_avg_args[] = {
+ IM_INPUT_IMAGE ("in"),
+ IM_OUTPUT_DOUBLE("x"),
+ IM_OUTPUT_DOUBLE("y"),
+ IM_OUTPUT_DOUBLE("out")
+};
+
+/* Call im_maxpos_avg via arg vector.
+ */
+static int
+maxpos_avg_vec( im_object *argv )
+{
+ return im_maxpos_avg( argv[0], argv[1], argv[2], argv[3] );
+}
+
+/* Description of im_maxpos_avg.
+ */
+static im_function maxpos_avg_desc = {
+ "im_maxpos_avg",
+ "position of maximum value of image, averaging in case of draw",
+ IM_FN_PIO,
+ maxpos_avg_vec,
+ IM_NUMBER( maxpos_avg_args ),
+ maxpos_avg_args
+};
+
+/* Args to im_min/maxpos_vec.
+ */
+static im_arg_desc maxpos_vec_args[] = {
+ IM_INPUT_IMAGE ("in"),
+ IM_INPUT_INT ("n"),
+ IM_OUTPUT_INTVEC("xes"),
+ IM_OUTPUT_INTVEC("yes"),
+ IM_OUTPUT_DOUBLEVEC("maxima")
+};
+
+/* Call im_maxpos_vec via arg vector.
+ */
+static int
+maxpos_vec_vec( im_object *argv )
+{
+ int n = *((int *) argv[1]);
+ im_intvec_object *xes = argv[2];
+ im_intvec_object *yes = argv[3];
+ im_doublevec_object *maxima = argv[4];
+
+ xes->vec = IM_ARRAY( NULL, n, int );
+ xes->n = n;
+ yes->vec = IM_ARRAY( NULL, n, int );
+ yes->n = n;
+ maxima->vec = IM_ARRAY( NULL, n, double );
+ maxima->n = n;
+ if( !xes->vec || !yes->vec || !maxima->vec ||
+ im_maxpos_vec( argv[0], xes->vec, yes->vec, maxima->vec, n ) )
+ return -1;
+
+ return 0;
+}
+
+/* Description of im_maxpos_vec.
+ */
+static im_function maxpos_vec_desc = {
+ "im_maxpos_vec",
+ "position and value of n maxima of image",
+ IM_FN_PIO,
+ maxpos_vec_vec,
+ IM_NUMBER( maxpos_vec_args ),
+ maxpos_vec_args
+};
+
+/* Call im_minpos_vec via arg vector.
+ */
+static int
+minpos_vec_vec( im_object *argv )
+{
+ int n = *((int *) argv[1]);
+ im_intvec_object *xes = argv[2];
+ im_intvec_object *yes = argv[3];
+ im_doublevec_object *minima = argv[4];
+
+ xes->vec = IM_ARRAY( NULL, n, int );
+ xes->n = n;
+ yes->vec = IM_ARRAY( NULL, n, int );
+ yes->n = n;
+ minima->vec = IM_ARRAY( NULL, n, double );
+ minima->n = n;
+ if( !xes->vec || !yes->vec || !minima->vec ||
+ im_minpos_vec( argv[0], xes->vec, yes->vec, minima->vec, n ) )
+ return -1;
+
+ return 0;
+}
+
+/* Description of im_minpos_vec.
+ */
+static im_function minpos_vec_desc = {
+ "im_minpos_vec",
+ "position and value of n minima of image",
+ IM_FN_PIO,
+ minpos_vec_vec,
+ IM_NUMBER( maxpos_vec_args ),
+ maxpos_vec_args
+};
+
+/* Args for measure.
+ */
+static im_arg_desc measure_args[] = {
+ IM_INPUT_IMAGE( "in" ),
+ IM_OUTPUT_DMASK( "mask" ),
+ IM_INPUT_INT( "x" ),
+ IM_INPUT_INT( "y" ),
+ IM_INPUT_INT( "w" ),
+ IM_INPUT_INT( "h" ),
+ IM_INPUT_INT( "h_patches" ),
+ IM_INPUT_INT( "v_patches" )
+};
+
+/* Call im_measure via arg vector.
+ */
+static int
+measure_vec( im_object *argv )
+{
+ IMAGE_BOX box;
+ int h, v, i;
+ int *sel;
+ int nsel;
+ im_mask_object *mo = argv[1];
+
+ box.xstart = *((int *) argv[2]);
+ box.ystart = *((int *) argv[3]);
+ box.xsize = *((int *) argv[4]);
+ box.ysize = *((int *) argv[5]);
+ box.chsel = 0;
+
+ h = *((int *) argv[6]);
+ v = *((int *) argv[7]);
+
+ nsel = h * v;
+ if( !(sel = IM_ARRAY( NULL, nsel, int )) )
+ return( -1 );
+ for( i = 0; i < nsel; i++ )
+ sel[i] = i + 1;
+
+ if( !(mo->mask =
+ im_measure( argv[0], &box, h, v, sel, nsel, mo->name )) ) {
+ im_free( sel );
+ return( -1 );
+ }
+ im_free( sel );
+
+ return( 0 );
+}
+
+/* Description of im_measure.
+ */
+static im_function measure_desc = {
+ "im_measure", /* Name */
+ N_( "measure averages of a grid of patches" ),
+ IM_FN_PIO, /* Flags */
+ measure_vec, /* Dispatch function */
+ IM_NUMBER( measure_args ), /* Size of arg list */
+ measure_args /* Arg list */
+};
+
+/* Call im_min via arg vector.
+ */
+static int
+min_vec( im_object *argv )
+{
+ double f;
+
+ if( im_min( argv[0], &f ) )
+ return( -1 );
+ *((double *) argv[1]) = f;
+
+ return( 0 );
+}
+
+/* Description of im_min.
+ */
+static im_function min_desc = {
+ "im_min", /* Name */
+ N_( "minimum value of image" ), /* Description */
+ IM_FN_PIO, /* Flags */
+ min_vec, /* Dispatch function */
+ IM_NUMBER( image_in_num_out ), /* Size of arg list */
+ image_in_num_out /* Arg list */
+};
+
+/* Call im_minpos via arg vector.
+ */
+static int
+minpos_vec( im_object *argv )
+{
+ double f;
+ int x, y;
+
+ if( im_minpos( argv[0], &x, &y, &f ) )
+ return( -1 );
+
+ ((double *) argv[1])[0] = x;
+ ((double *) argv[1])[1] = y;
+
+ return( 0 );
+}
+
+/* Description of im_minpos.
+ */
+static im_function minpos_desc = {
+ "im_minpos", /* Name */
+ N_( "position of minimum value of image" ),
+ 0, /* Flags */
+ minpos_vec, /* Dispatch function */
+ IM_NUMBER( maxpos_args ), /* Size of arg list */
+ maxpos_args /* Arg list */
+};
+
+/* Call im_remainder via arg vector.
+ */
+static int
+remainder_vec( im_object *argv )
+{
+ return( im_remainder( argv[0], argv[1], argv[2] ) );
+}
+
+/* Description of im_remainder.
+ */
+static im_function remainder_desc = {
+ "im_remainder", /* Name */
+ N_( "remainder after integer division" ), /* Description */
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ remainder_vec, /* Dispatch function */
+ IM_NUMBER( two_in_one_out ), /* Size of arg list */
+ two_in_one_out /* Arg list */
+};
+
+/* Call im_remainderconst via arg vector.
+ */
+static int
+remainderconst_vec( im_object *argv )
+{
+ double c = *((double *) argv[2]);
+
+ return( im_remainderconst( argv[0], argv[1], c ) );
+}
+
+/* Args for im_remainderconst().
+ */
+static im_arg_desc remainderconst_args[] = {
+ IM_INPUT_IMAGE( "in" ),
+ IM_OUTPUT_IMAGE( "out" ),
+ IM_INPUT_DOUBLE( "x" )
+};
+
+/* Description of im_remainderconst.
+ */
+static im_function remainderconst_desc = {
+ "im_remainderconst", /* Name */
+ N_( "remainder after integer division by a constant" ),/* Description */
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ remainderconst_vec, /* Dispatch function */
+ IM_NUMBER( remainderconst_args ), /* Size of arg list */
+ remainderconst_args /* Arg list */
+};
+
+/* Call im_remainderconst_vec via arg vector.
+ */
+static int
+remainderconst_vec_vec( im_object *argv )
+{
+ im_doublevec_object *dv = (im_doublevec_object *) argv[2];
+
+ return( im_remainderconst_vec( argv[0], argv[1], dv->n, dv->vec ) );
+}
+
+/* Args for im_remainderconst_vec().
+ */
+static im_arg_desc remainderconst_vec_args[] = {
+ IM_INPUT_IMAGE( "in" ),
+ IM_OUTPUT_IMAGE( "out" ),
+ IM_INPUT_DOUBLEVEC( "x" )
+};
+
+/* Description of im_remainderconst_vec.
+ */
+static im_function remainderconst_vec_desc = {
+ "im_remainderconst_vec", /* Name */
+ N_( "remainder after integer division by a vector of constants" ),
+ /* Description */
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ remainderconst_vec_vec, /* Dispatch function */
+ IM_NUMBER( remainderconst_vec_args ), /* Size of arg list */
+ remainderconst_vec_args /* Arg list */
+};
+
+/* Call im_multiply via arg vector.
+ */
+static int
+multiply_vec( im_object *argv )
+{
+ return( im_multiply( argv[0], argv[1], argv[2] ) );
+}
+
+/* Description of im_multiply.
+ */
+static im_function multiply_desc = {
+ "im_multiply", /* Name */
+ N_( "multiply two images" ), /* Description */
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ multiply_vec, /* Dispatch function */
+ IM_NUMBER( two_in_one_out ), /* Size of arg list */
+ two_in_one_out /* Arg list */
+};
+
+/* Call im_powtra() via arg vector.
+ */
+static int
+powtra_vec( im_object *argv )
+{
+ double a = *((double *) argv[2]);
+
+ return( im_powtra( argv[0], argv[1], a ) );
+}
+
+/* Description of im_powtra().
+ */
+static im_function powtra_desc = {
+ "im_powtra", /* Name */
+ N_( "pel^x ofbuildimage" ),
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ powtra_vec, /* Dispatch function */
+ IM_NUMBER( powtra_args ), /* Size of arg list */
+ powtra_args /* Arg list */
+};
+
+/* Call im_powtra_vec() via arg vector.
+ */
+static int
+powtra_vec_vec( im_object *argv )
+{
+ im_doublevec_object *rv = (im_doublevec_object *) argv[2];
+
+ return( im_powtra_vec( argv[0], argv[1], rv->n, rv->vec ) );
+}
+
+/* Description of im_powtra_vec().
+ */
+static im_function powtra_vec_desc = {
+ "im_powtra_vec", /* Name */
+ N_( "pel^[x,y,z] of image" ),
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ powtra_vec_vec, /* Dispatch function */
+ IM_NUMBER( expntra_vec_args ), /* Size of arg list */
+ expntra_vec_args /* Arg list */
+};
+
+/* Args for im_stats.
+ */
+static im_arg_desc stats_args[] = {
+ IM_INPUT_IMAGE( "in" ),
+ IM_OUTPUT_DMASK_STATS( "statistics" )
+};
+
+/* Call im_stats() via arg vector.
+ */
+static int
+stats_vec( im_object *argv )
+{
+ im_mask_object *mo = argv[1];
+
+ if( !(mo->mask = im_stats( argv[0] )) )
+ return( -1 );
+
+ return( 0 );
+}
+
+/* Description of im_stats().
+ */
+static im_function stats_desc = {
+ "im_stats", /* Name */
+ N_( "many image statistics in one pass" ),
+ IM_FN_PIO, /* Flags */
+ stats_vec, /* Dispatch function */
+ IM_NUMBER( stats_args ), /* Size of arg list */
+ stats_args /* Arg list */
+};
+
+/* Call im_subtract via arg vector.
+ */
+static int
+subtract_vec( im_object *argv )
+{
+ return( im_subtract( argv[0], argv[1], argv[2] ) );
+}
+
+/* Description of im_subtract.
+ */
+static im_function subtract_desc = {
+ "im_subtract", /* Name */
+ N_( "subtract two images" ), /* Description */
+ IM_FN_PIO, /* Flags */
+ subtract_vec, /* Dispatch function */
+ IM_NUMBER( two_in_one_out ), /* Size of arg list */
+ two_in_one_out /* Arg list */
+};
+
+/* Args for im_linreg.
+ */
+static im_arg_desc linreg_args[] = {
+ IM_INPUT_IMAGEVEC( "ins" ),
+ IM_OUTPUT_IMAGE( "out" ),
+ IM_INPUT_DOUBLEVEC( "xs" )
+};
+
+/* Call im_linreg() via arg vector.
+ */
+static int
+linreg_vec( im_object *argv )
+{
+#define FUNCTION_NAME "im_linreg_vec"
+ im_imagevec_object *ins_vec= (im_imagevec_object*) argv[0];
+ im_doublevec_object *xs_vec= (im_doublevec_object*) argv[2];
+ IMAGE *out= (IMAGE*) argv[1];
+ IMAGE **ins= IM_ARRAY( out, ins_vec-> n + 1, IMAGE* );
+ int i;
+
+ if( ! ins )
+ return -1;
+
+ for( i= 0; i < ins_vec-> n; ++i )
+ ins[ i ]= ins_vec-> vec[ i ];
+
+ ins[ ins_vec-> n ]= NULL;
+
+ if( xs_vec-> n != ins_vec-> n ){
+ im_error( FUNCTION_NAME, "image vector and x vector differ in length" );
+ return -1;
+ }
+ return im_linreg( ins, out, xs_vec-> vec );
+
+#undef FUNCTION_NAME
+}
+
+/* Description of im_linreg().
+ */
+static im_function linreg_desc = {
+ "im_linreg", /* Name */
+ N_( "pixelwise linear regression" ),
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ linreg_vec, /* Dispatch function */
+ IM_NUMBER( linreg_args ), /* Size of arg list */
+ linreg_args /* Arg list */
+};
+
+/* Call im_cross_phase via arg vector.
+ */
+static int
+cross_phase_vec( im_object *argv )
+{
+ return( im_cross_phase( argv[0], argv[1], argv[2] ) );
+}
+
+/* Description of im_cross_phase.
+ */
+static im_function cross_phase_desc = {
+ "im_cross_phase", /* Name */
+ N_( "phase of cross power spectrum of two complex images" ), /* Description */
+ IM_FN_PIO | IM_FN_PTOP, /* Flags */
+ cross_phase_vec, /* Dispatch function */
+ IM_NUMBER( two_in_one_out ), /* Size of arg list */
+ two_in_one_out /* Arg list */
+};
+
+/* Package up all these functions.
+ */
+static im_function *arith_list[] = {
+ &abs_desc,
+ &acostra_desc,
+ &add_desc,
+ &asintra_desc,
+ &atantra_desc,
+ &avg_desc,
+ &point_bilinear_desc,
+ &bandmean_desc,
+ &ceil_desc,
+ &cmulnorm_desc,
+ &costra_desc,
+ &cross_phase_desc,
+ &deviate_desc,
+ ÷_desc,
+ &exp10tra_desc,
+ &expntra_desc,
+ &expntra_vec_desc,
+ &exptra_desc,
+ &fav4_desc,
+ &floor_desc,
+ &gadd_desc,
+ &invert_desc,
+ &lintra_desc,
+ &linreg_desc,
+ &lintra_vec_desc,
+ &litecor_desc,
+ &log10tra_desc,
+ &logtra_desc,
+ &max_desc,
+ &maxpos_desc,
+ &maxpos_avg_desc,
+ &maxpos_vec_desc,
+ &measure_desc,
+ &min_desc,
+ &minpos_desc,
+ &minpos_vec_desc,
+ &multiply_desc,
+ &powtra_desc,
+ &powtra_vec_desc,
+ &remainder_desc,
+ &remainderconst_desc,
+ &remainderconst_vec_desc,
+ &rint_desc,
+ &sign_desc,
+ &sintra_desc,
+ &stats_desc,
+ &subtract_desc,
+ &tantra_desc
+};
+
+/* Package of functions.
+ */
+im_package im__arithmetic = {
+ "arithmetic",
+ IM_NUMBER( arith_list ),
+ arith_list
+};
diff --git a/libvips/arithmetic/im_abs.c b/libvips/arithmetic/im_abs.c
new file mode 100644
index 00000000..7305ddd3
--- /dev/null
+++ b/libvips/arithmetic/im_abs.c
@@ -0,0 +1,272 @@
+/* im_abs()
+ *
+ * Copyright: 1990, N. Dessipris, based on im_powtra()
+ * Author: Nicos Dessipris
+ * Written on: 02/05/1990
+ * Modified on:
+ * 5/5/93 J.Cupitt
+ * - adapted from im_lintra to work with partial images
+ * - complex and signed support added
+ * 30/6/93 JC
+ * - adapted for partial v2
+ * - ANSI conversion
+ * - spe29873r6k3h()**!@lling errors removed
+ * 9/2/95 JC
+ * - adapted for im_wrap...
+ * 20/6/02 JC
+ * - tiny speed up
+ * 8/12/06
+ * - add liboil support
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#ifdef HAVE_LIBOIL
+#include
+#endif /*HAVE_LIBOIL*/
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* Integer abs operation: just test and negate.
+ */
+#define intabs(TYPE) \
+ { \
+ TYPE *p = (TYPE *) in; \
+ TYPE *q = (TYPE *) out; \
+ int x; \
+ \
+ for( x = 0; x < sz; x++ ) { \
+ TYPE v = p[x]; \
+ \
+ if( v < 0 ) \
+ q[x] = 0 - v; \
+ else \
+ q[x] = v; \
+ } \
+ }
+
+/* Float abs operation: call fabs().
+ */
+#define floatabs(TYPE)\
+ {\
+ TYPE *p = (TYPE *) in;\
+ TYPE *q = (TYPE *) out;\
+ int x; \
+ \
+ for( x = 0; x < sz; x++ )\
+ q[x] = fabs( p[x] );\
+ }
+
+/* Complex abs operation: calculate modulus.
+ */
+
+#ifdef HAVE_HYPOT
+
+#define complexabs(TYPE) { \
+ TYPE *p = (TYPE *) in; \
+ TYPE *q = (TYPE *) out; \
+ int i; \
+ \
+ for( i = 0; i < sz; i++ ) { \
+ q[i] = hypot( p[0], p[1] ); \
+ p += 2; \
+ } \
+ }
+
+#else /*HAVE_HYPOT*/
+
+#define complexabs(TYPE) { \
+ TYPE *p = (TYPE *) in; \
+ TYPE *q = (TYPE *) out; \
+ TYPE *q_stop = q + sz; \
+ \
+ while( q < q_stop ){ \
+ double rp = *p++; \
+ double ip = *p++; \
+ double abs_rp= fabs( rp ); \
+ double abs_ip= fabs( ip ); \
+ \
+ if( abs_rp > abs_ip ){ \
+ double temp= ip / rp; \
+ *q++= abs_rp * sqrt( 1.0 + temp * temp ); \
+ } \
+ else { \
+ double temp= rp / ip; \
+ *q++= abs_ip * sqrt( 1.0 + temp * temp ); \
+ } \
+ } \
+ }
+
+#endif /*HAVE_HYPOT*/
+
+/* Abs a buffer of PELs.
+ */
+static void
+abs_gen( PEL *in, PEL *out, int width, IMAGE *im )
+{
+ int sz = width * im->Bands;
+
+ /* Abs all input types.
+ */
+ switch( im->BandFmt ) {
+ case IM_BANDFMT_CHAR:
+#ifdef HAVE_LIBOIL
+ oil_abs_u8_s8( (uint8_t *) out, sizeof( uint8_t ),
+ (int8_t *) in, sizeof( int8_t ), sz );
+#else /*!HAVE_LIBOIL*/
+ intabs( signed char );
+#endif /*HAVE_LIBOIL*/
+ break;
+
+ case IM_BANDFMT_SHORT:
+#ifdef HAVE_LIBOIL
+ oil_abs_u16_s16( (uint16_t *) out, sizeof( uint16_t ),
+ (int16_t *) in, sizeof( int16_t ), sz );
+#else /*!HAVE_LIBOIL*/
+ intabs( signed short );
+#endif /*HAVE_LIBOIL*/
+ break;
+
+ case IM_BANDFMT_INT:
+#ifdef HAVE_LIBOIL
+ oil_abs_u32_s32( (uint32_t *) out, sizeof( uint32_t ),
+ (int32_t *) in, sizeof( int32_t ), sz );
+#else /*!HAVE_LIBOIL*/
+ intabs( signed int );
+#endif /*HAVE_LIBOIL*/
+ break;
+
+ case IM_BANDFMT_FLOAT:
+#ifdef HAVE_LIBOIL
+ oil_abs_f32_f32( (float *) out, sizeof( float ),
+ (float *) in, sizeof( float ), sz );
+#else /*!HAVE_LIBOIL*/
+ floatabs( float );
+#endif /*HAVE_LIBOIL*/
+ break;
+
+ case IM_BANDFMT_DOUBLE:
+#ifdef HAVE_LIBOIL
+ oil_abs_f64_f64( (double *) out, sizeof( double ),
+ (double *) in, sizeof( double ), sz );
+#else /*!HAVE_LIBOIL*/
+ floatabs( float );
+#endif /*HAVE_LIBOIL*/
+ break;
+
+ case IM_BANDFMT_COMPLEX: complexabs( float ); break;
+ case IM_BANDFMT_DPCOMPLEX: complexabs( double ); break;
+
+ default:
+ assert( 0 );
+ }
+}
+
+/**
+ * im_abs:
+ * @in: input #IMAGE
+ * @out: output #IMAGE
+ *
+ * This operation finds the absolute value of an image. It does a copy for
+ * unsigned integer types, negate for negative values in
+ * signed integer types, fabs(3) for
+ * float types, and calculate modulus for complex
+ * types.
+ *
+ * See also: im_exp10tra(), im_sign().
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int
+im_abs( IMAGE *in, IMAGE *out )
+{
+ /* Check args.
+ */
+ if( in->Coding != IM_CODING_NONE ) {
+ im_error( "im_abs", "%s", _( "not uncoded" ) );
+ return( -1 );
+ }
+
+ /* Is this one of the unsigned types? Degenerate to im_copy() if it
+ * is.
+ */
+ if( im_isuint( in ) )
+ return( im_copy( in, out ) );
+
+ /* Prepare output header. Output type == input type, except for
+ * complex.
+ */
+ if( im_cp_desc( out, in ) )
+ return( -1 );
+ switch( in->BandFmt ) {
+ case IM_BANDFMT_CHAR:
+ case IM_BANDFMT_SHORT:
+ case IM_BANDFMT_INT:
+ case IM_BANDFMT_FLOAT:
+ case IM_BANDFMT_DOUBLE:
+ /* No action.
+ */
+ break;
+
+ case IM_BANDFMT_COMPLEX:
+ out->Bbits = IM_BBITS_FLOAT;
+ out->BandFmt = IM_BANDFMT_FLOAT;
+ break;
+
+ case IM_BANDFMT_DPCOMPLEX:
+ out->Bbits = IM_BBITS_DOUBLE;
+ out->BandFmt = IM_BANDFMT_DOUBLE;
+ break;
+
+ default:
+ im_error( "im_abs", "%s", _( "unknown input type" ) );
+ return( -1 );
+ }
+
+ /* Generate!
+ */
+ if( im_wrapone( in, out,
+ (im_wrapone_fn) abs_gen, in, NULL ) )
+ return( -1 );
+
+ return( 0 );
+}
diff --git a/libvips/arithmetic/im_add.c b/libvips/arithmetic/im_add.c
new file mode 100644
index 00000000..a7ae3351
--- /dev/null
+++ b/libvips/arithmetic/im_add.c
@@ -0,0 +1,381 @@
+/* im_add.c
+ *
+ * Copyright: 1990, N. Dessipris.
+ *
+ * Author: Nicos Dessipris
+ * Written on: 02/05/1990
+ * Modified on:
+ * 29/4/93 J.Cupitt
+ * - now works for partial images
+ * 1/7/93 JC
+ * - adapted for partial v2
+ * 9/5/95 JC
+ * - simplified: now just handles 10 cases (instead of 50), using
+ * im_clip2*() to help
+ * - now uses im_wrapmany() rather than im_generate()
+ * 31/5/96 JC
+ * - SWAP() removed, *p++ removed
+ * 27/9/04
+ * - im__cast_and_call() now matches bands as well
+ * - ... so 1 band + 4 band image -> 4 band image
+ * 8/12/06
+ * - add liboil support
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#ifdef HAVE_LIBOIL
+#include
+#endif /*HAVE_LIBOIL*/
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* Complex add.
+ */
+#define cloop(TYPE) { \
+ TYPE *p1 = (TYPE *) in[0]; \
+ TYPE *p2 = (TYPE *) in[1]; \
+ TYPE *q = (TYPE *) out; \
+ \
+ for( x = 0; x < sz; x++ ) { \
+ double rp1 = p1[0]; \
+ double ip1 = p1[1]; \
+ \
+ double rp2 = p2[0]; \
+ double ip2 = p2[1]; \
+ \
+ p1 += 2; \
+ p2 += 2; \
+ \
+ q[0] = rp1 + rp2; \
+ q[1] = ip1 + ip2; \
+ \
+ q += 2; \
+ } \
+}
+
+/* Real add.
+ */
+#define rloop(IN, OUT) { \
+ IN *p1 = (IN *) in[0]; \
+ IN *p2 = (IN *) in[1]; \
+ OUT *q = (OUT *) out; \
+ \
+ for( x = 0; x < sz; x++ ) \
+ q[x] = p1[x] + p2[x]; \
+}
+
+static void
+add_buffer( PEL **in, PEL *out, int width, IMAGE *im )
+{
+ int x;
+ int sz = width * im->Bands;
+
+ /* Add all input types. Kep types here in sync with bandfmt_add[] below.
+ */
+ switch( im->BandFmt ) {
+ case IM_BANDFMT_UCHAR: rloop( unsigned char, unsigned short ); break;
+ case IM_BANDFMT_CHAR: rloop( signed char, signed short ); break;
+ case IM_BANDFMT_USHORT: rloop( unsigned short, unsigned int ); break;
+ case IM_BANDFMT_SHORT: rloop( signed short, signed int ); break;
+ case IM_BANDFMT_UINT: rloop( unsigned int, unsigned int ); break;
+ case IM_BANDFMT_INT: rloop( signed int, signed int ); break;
+
+ case IM_BANDFMT_FLOAT:
+#ifdef HAVE_LIBOIL
+ oil_add_f32( (float *) out,
+ (float *) in[0], (float *) in[1], sz );
+#else /*!HAVE_LIBOIL*/
+ rloop( float, float );
+#endif /*HAVE_LIBOIL*/
+ break;
+
+ case IM_BANDFMT_DOUBLE: rloop( double, double ); break;
+ case IM_BANDFMT_COMPLEX:cloop( float ); break;
+ case IM_BANDFMT_DPCOMPLEX:cloop( double ); break;
+
+ default:
+ assert( 0 );
+ }
+}
+
+/* Save a bit of typing.
+ */
+#define UC IM_BANDFMT_UCHAR
+#define C IM_BANDFMT_CHAR
+#define US IM_BANDFMT_USHORT
+#define S IM_BANDFMT_SHORT
+#define UI IM_BANDFMT_UINT
+#define I IM_BANDFMT_INT
+#define F IM_BANDFMT_FLOAT
+#define M IM_BANDFMT_COMPLEX
+#define D IM_BANDFMT_DOUBLE
+#define DM IM_BANDFMT_DPCOMPLEX
+
+/* For two integer types, the "largest", ie. one which can represent the
+ * full range of both.
+ */
+static int bandfmt_largest[6][6] = {
+ /* UC C US S UI I */
+/* UC */ { UC, S, US, S, UI, I },
+/* C */ { S, C, I, S, I, I },
+/* US */ { US, I, US, I, UI, I },
+/* S */ { S, S, I, S, I, I },
+/* UI */ { UI, I, UI, I, UI, I },
+/* I */ { I, I, I, I, I, I }
+};
+
+/* For two formats, find one which can represent the full range of both.
+ */
+static VipsBandFmt
+im__format_common( IMAGE *in1, IMAGE *in2 )
+{
+ if( im_iscomplex( in1 ) || im_iscomplex( in2 ) ) {
+ /* What kind of complex?
+ */
+ if( in1->BandFmt == IM_BANDFMT_DPCOMPLEX ||
+ in2->BandFmt == IM_BANDFMT_DPCOMPLEX )
+ /* Output will be DPCOMPLEX.
+ */
+ return( IM_BANDFMT_DPCOMPLEX );
+ else
+ return( IM_BANDFMT_COMPLEX );
+
+ }
+ else if( im_isfloat( in1 ) || im_isfloat( in2 ) ) {
+ /* What kind of float?
+ */
+ if( in1->BandFmt == IM_BANDFMT_DOUBLE ||
+ in2->BandFmt == IM_BANDFMT_DOUBLE )
+ return( IM_BANDFMT_DOUBLE );
+ else
+ return( IM_BANDFMT_FLOAT );
+ }
+ else
+ /* Must be int+int -> int.
+ */
+ return( bandfmt_largest[in1->BandFmt][in2->BandFmt] );
+}
+
+/* Make an n-band image. Input 1 or n bands.
+ */
+static int
+im__bandup( IMAGE *in, IMAGE *out, int n )
+{
+ IMAGE *bands[256];
+ int i;
+
+ if( in->Bands == n )
+ return( im_copy( in, out ) );
+ if( in->Bands != 1 ) {
+ im_error( "im__bandup", _( "not one band or %d bands" ), n );
+ return( -1 );
+ }
+ if( n > 256 || n < 1 ) {
+ im_error( "im__bandup", "%s", _( "bad bands" ) );
+ return( -1 );
+ }
+
+ for( i = 0; i < n; i++ )
+ bands[i] = in;
+
+ return( im_gbandjoin( bands, out, n ) );
+}
+
+/* Cast in1 and in2 up to a common type and number of bands, then call the
+ * function. Also used by subtract, multiply, divide, etc.
+ */
+int
+im__cast_and_call( IMAGE *in1, IMAGE *in2, IMAGE *out,
+ im_wrapmany_fn fn, void *a )
+{
+ VipsBandFmt fmt;
+ IMAGE *t[5];
+
+ if( im_open_local_array( out, t, 4, "type cast:1", "p" ) )
+ return( -1 );
+
+ /* Cast our input images up to a common type.
+ */
+ fmt = im__format_common( in1, in2 );
+ if( im_clip2fmt( in1, t[0], fmt ) ||
+ im_clip2fmt( in2, t[1], fmt ) )
+ return( -1 );
+
+ /* Force bands up to the same as out.
+ */
+ if( im__bandup( t[0], t[2], out->Bands ) ||
+ im__bandup( t[1], t[3], out->Bands ) )
+ return( -1 );
+
+ /* And process!
+ */
+ t[4] = NULL;
+ if( im_wrapmany( t + 2, out, fn, out, a ) )
+ return( -1 );
+
+ return( 0 );
+}
+
+/* Type promotion for addition. Sign and value preserving. Make sure these
+ * match the case statement in add_buffer() above.
+ */
+static int bandfmt_add[10] = {
+/* UC C US S UI I F M D DM */
+ US, S, UI, I, UI, I, F, M, D, DM
+};
+
+/**
+ * im_add:
+ * @in1: input image 1
+ * @in2: input image 2
+ * @out: output image
+ *
+ * This operation adds corresponding pixels in images @in1 and
+ * @in2 and writes the result to the image descriptor @out. The images must be
+ * the same size, but may have any type. If one of the images has a single
+ * band, it is added to every band of the other image.
+ *
+ * The two input images are cast up to the smallest common type (see table
+ * Smallest common format in
+ * arithmetic), then the
+ * following table is used to determine the output type:
+ *
+ *
+ * im_add() type promotion
+ *
+ *
+ *
+ * input type
+ * output type
+ *
+ *
+ *
+ *
+ * uchar
+ * ushort
+ *
+ *
+ * char
+ * short
+ *
+ *
+ * ushort
+ * uint
+ *
+ *
+ * short
+ * int
+ *
+ *
+ * uint
+ * uint
+ *
+ *
+ * int
+ * int
+ *
+ *
+ * float
+ * float
+ *
+ *
+ * double
+ * double
+ *
+ *
+ * complex
+ * complex
+ *
+ *
+ * double complex
+ * double complex
+ *
+ *
+ *
+ *
+ *
+ * In other words, the output type is just large enough to hold the whole
+ * range of possible values.
+ *
+ * See also: im_subtract(), im_lintra().
+ *
+ * Returns: 0 on success, -1 on error
+ */
+int
+im_add( IMAGE *in1, IMAGE *in2, IMAGE *out )
+{
+ /* Basic checks.
+ */
+ if( im_piocheck( in1, out ) || im_pincheck( in2 ) )
+ return( -1 );
+ if( in1->Bands != in2->Bands &&
+ (in1->Bands != 1 && in2->Bands != 1) ) {
+ im_error( "im_add", "%s", _( "not same number of bands" ) );
+ return( -1 );
+ }
+ if( in1->Coding != IM_CODING_NONE || in2->Coding != IM_CODING_NONE ) {
+ im_error( "im_add", "%s", _( "not uncoded" ) );
+ return( -1 );
+ }
+ if( im_cp_descv( out, in1, in2, NULL ) )
+ return( -1 );
+
+ /* What number of bands will we write?
+ */
+ out->Bands = IM_MAX( in1->Bands, in2->Bands );
+
+ /* What output type will we write? int, float or complex.
+ */
+ out->BandFmt = bandfmt_add[im__format_common( in1, in2 )];
+ out->Bbits = im_bits_of_fmt( out->BandFmt );
+
+ /* And process!
+ */
+ if( im__cast_and_call( in1, in2, out,
+ (im_wrapmany_fn) add_buffer, NULL ) )
+ return( -1 );
+
+ /* Success!
+ */
+ return( 0 );
+}
diff --git a/libvips/arithmetic/im_avg.c b/libvips/arithmetic/im_avg.c
new file mode 100644
index 00000000..21aac595
--- /dev/null
+++ b/libvips/arithmetic/im_avg.c
@@ -0,0 +1,207 @@
+/* @(#) Find the average of an image. Takes any non-complex image format,
+ * @(#) returns a double. Finds the average of all bands.
+ * @(#)
+ * @(#) int
+ * @(#) im_avg( im, out )
+ * @(#) IMAGE *im;
+ * @(#) double *out;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error.
+ *
+ * Copyright: 1990, J. Cupitt
+ *
+ * Author: J. Cupitt
+ * Written on: 02/08/1990
+ * Modified on:
+ * 5/5/93 JC
+ * - now does partial images
+ * - less likely to overflow
+ * 1/7/93 JC
+ * - adapted for partial v2
+ * - ANSI C
+ * 21/2/95 JC
+ * - modernised again
+ * 11/5/95 JC
+ * - oops! return( NULL ) in im_avg(), instead of return( -1 )
+ * 20/6/95 JC
+ * - now returns double
+ * 13/1/05
+ * - use 64 bit arithmetic
+ * 8/12/06
+ * - add liboil support
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#ifdef HAVE_LIBOIL
+#include
+#endif /*HAVE_LIBOIL*/
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* Start function: allocate space for a double in which we can accululate the
+ * sum.
+ */
+static void *
+start_fn( IMAGE *out, void *a, void *b )
+{
+ double *tmp;
+
+ if( !(tmp = IM_ARRAY( out, 1, double )) )
+ return( NULL );
+ *tmp = 0.0;
+
+ return( (void *) tmp );
+}
+
+/* Stop function. Add this little sum to the main sum.
+ */
+static int
+stop_fn( void *seq, void *a, void *b )
+{
+ double *tmp = (double *) seq;
+ double *sum = (double *) a;
+
+ *sum += *tmp;
+
+ return( 0 );
+}
+
+/* Loop over region, accumulating a sum in *tmp.
+ */
+static int
+scan_fn( REGION *reg, void *seq, void *a, void *b )
+{
+ double *tmp = (double *) seq;
+ Rect *r = ®->valid;
+ IMAGE *im = reg->im;
+ int le = r->left;
+ int to = r->top;
+ int bo = IM_RECT_BOTTOM(r);
+ int sz = IM_REGION_N_ELEMENTS( reg );
+ double sum = 0.0;
+ int x, y;
+
+/* Sum pels in this section.
+ */
+#define loop(TYPE) \
+ { TYPE *p;\
+ \
+ for( y = to; y < bo; y++ ) { \
+ p = (TYPE *) IM_REGION_ADDR( reg, le, y ); \
+ \
+ for( x = 0; x < sz; x++ ) \
+ sum += *p++;\
+ }\
+ }
+
+ /* Now generate code for all types.
+ */
+ switch( im->BandFmt ) {
+ case IM_BANDFMT_UCHAR: loop(unsigned char); break;
+ case IM_BANDFMT_CHAR: loop(signed char); break;
+ case IM_BANDFMT_USHORT: loop(unsigned short); break;
+ case IM_BANDFMT_SHORT: loop(signed short); break;
+ case IM_BANDFMT_UINT: loop(unsigned int); break;
+ case IM_BANDFMT_INT: loop(signed int); break;
+ case IM_BANDFMT_FLOAT: loop(float); break;
+
+ case IM_BANDFMT_DOUBLE:
+#ifdef HAVE_LIBOIL
+ for( y = to; y < bo; y++ ) {
+ double *p = (double *) IM_REGION_ADDR( reg, le, y );
+ double t;
+
+ oil_sum_f64( &t, p, sizeof( double ), sz );
+
+ sum += t;
+ }
+#else /*!HAVE_LIBOIL*/
+ loop(double);
+#endif /*HAVE_LIBOIL*/
+ break;
+
+ default:
+ assert( 0 );
+ }
+
+ /* Add to sum for this sequence.
+ */
+ *tmp += sum;
+
+ return( 0 );
+}
+
+/* Find the average of an image.
+ */
+int
+im_avg( IMAGE *in, double *out )
+{
+ double sum = 0.0;
+ gint64 vals, pels;
+
+ /* Check our args.
+ */
+ if( im_pincheck( in ) )
+ return( -1 );
+ if( im_iscomplex( in ) ) {
+ im_error( "im_avg", "%s", _( "bad input type" ) );
+ return( -1 );
+ }
+ if( in->Coding != IM_CODING_NONE ) {
+ im_error( "im_avg", "%s", _( "not uncoded" ) );
+ return( -1 );
+ }
+
+ /* Loop over input, summing pixels.
+ */
+ if( im_iterate( in, start_fn, scan_fn, stop_fn, &sum, NULL ) )
+ return( -1 );
+
+ /* Calculate and return average.
+ */
+ pels = (gint64) in->Xsize * in->Ysize;
+ vals = pels * in->Bands;
+ *out = sum / vals;
+
+ return( 0 );
+}
diff --git a/libvips/arithmetic/im_bandmean.c b/libvips/arithmetic/im_bandmean.c
new file mode 100644
index 00000000..dd602afb
--- /dev/null
+++ b/libvips/arithmetic/im_bandmean.c
@@ -0,0 +1,161 @@
+/* @(#) Average the bands in an image.
+ * @(#)
+ * @(#) int
+ * @(#) im_bandmean(in, out)
+ * @(#) IMAGE *in, *out;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ *
+ * Author: Simon Goodall
+ * Written on: 17/7/07
+ * 17/7/07 JC
+ * - hacked about a bit
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+
+#include
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* Int types. Round, keep sum in a larger variable.
+ */
+#define ILOOP( TYPE, STYPE ) { \
+ TYPE *p1 = (TYPE *) p; \
+ TYPE *q1 = (TYPE *) q; \
+ \
+ for( i = 0; i < n; i++ ) { \
+ STYPE sum; \
+ \
+ sum = 0; \
+ for( j = 0; j < b; j++ ) \
+ sum += p1[j]; \
+ *q1++ = sum > 0 ? (sum + b / 2) / b : (sum - b / 2) / b; \
+ p1 += b; \
+ } \
+}
+
+/* Float loop. No rounding, sum in same container.
+ */
+#define FLOOP( TYPE ) { \
+ TYPE *p1 = (TYPE *) p; \
+ TYPE *q1 = (TYPE *) q; \
+ \
+ for( i = 0; i < n; i++ ) { \
+ TYPE sum; \
+ \
+ sum = 0; \
+ for( j = 0; j < b; j++ ) \
+ sum += p1[j]; \
+ *q1++ = sum / b; \
+ p1 += b; \
+ } \
+}
+
+/* Complex loop. Mean reals and imaginaries separately.
+ */
+#define CLOOP( TYPE ) { \
+ TYPE *p1 = (TYPE *) p; \
+ TYPE *q1 = (TYPE *) q; \
+ \
+ for( i = 0; i < n * 2; i += 2 ) { \
+ TYPE sum; \
+ \
+ sum = 0; \
+ for( j = 0; j < b; j++ ) \
+ sum += p1[j * 2]; \
+ q1[0] = sum / b; \
+ sum = 0; \
+ for( j = 0; j < b; j++ ) \
+ sum += p1[j * 2 + 1]; \
+ q1[1] = sum / b; \
+ p1 += b; \
+ q1 += 2; \
+ } \
+}
+
+static void
+bandmean_buffer( PEL *p, PEL *q, int n, IMAGE *in )
+{
+ int i, j;
+ const int b = in->Bands;
+
+ switch( in->BandFmt ) {
+ case IM_BANDFMT_CHAR: ILOOP( signed char, int ); break;
+ case IM_BANDFMT_UCHAR: ILOOP( unsigned char, unsigned int ); break;
+ case IM_BANDFMT_SHORT: ILOOP( signed short, int ); break;
+ case IM_BANDFMT_USHORT: ILOOP( unsigned short, unsigned int ); break;
+ case IM_BANDFMT_INT: ILOOP( signed int, int ); break;
+ case IM_BANDFMT_UINT: ILOOP( unsigned int, unsigned int ); break;
+ case IM_BANDFMT_FLOAT: FLOOP( float ); break;
+ case IM_BANDFMT_DOUBLE: FLOOP( double ); break;
+ case IM_BANDFMT_COMPLEX: CLOOP( float ); break;
+ case IM_BANDFMT_DPCOMPLEX: CLOOP( double ); break;
+
+ default:
+ assert( 0 );
+ }
+}
+
+int
+im_bandmean( IMAGE *in, IMAGE *out )
+{
+ /* Check input params
+ */
+ if( in->Bands == 1 )
+ return( im_copy( in, out ) );
+ if( in->Coding != IM_CODING_NONE ) {
+ im_error( "im_bandmean", "%s", _( "uncoded multiband only" ) );
+ return( -1 );
+ }
+
+ /* Prepare output image.
+ */
+ if( im_cp_desc( out, in ) )
+ return( -1 );
+ out->Bands = 1;
+ out->Type = IM_TYPE_B_W;
+
+ /* And process!
+ */
+ if( im_wrapone( in, out,
+ (im_wrapone_fn) bandmean_buffer, in, NULL ) )
+ return( -1 );
+
+ return( 0 );
+}
+
diff --git a/libvips/arithmetic/im_ceil.c b/libvips/arithmetic/im_ceil.c
new file mode 100644
index 00000000..eb3eb290
--- /dev/null
+++ b/libvips/arithmetic/im_ceil.c
@@ -0,0 +1,114 @@
+/* @(#) ceil() an image ... no promotion, so output type == input type
+ * @(#)
+ * @(#) int
+ * @(#) im_ceil( in, out )
+ * @(#) IMAGE *in, *out;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ * @(#)
+ *
+ * 20/6/02 JC
+ * - adapted from im_abs()
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+#define ceil_loop(TYPE)\
+ {\
+ TYPE *p = (TYPE *) in;\
+ TYPE *q = (TYPE *) out;\
+ \
+ for( x = 0; x < sz; x++ )\
+ q[x] = ceil( p[x] );\
+ }
+
+/* Ceil a buffer of PELs.
+ */
+static void
+ceil_gen( PEL *in, PEL *out, int width, IMAGE *im )
+{
+ int x;
+ int sz = width * im->Bands;
+
+ switch( im->BandFmt ) {
+ case IM_BANDFMT_FLOAT: ceil_loop(float); break;
+ case IM_BANDFMT_DOUBLE: ceil_loop(double); break;
+ case IM_BANDFMT_COMPLEX: sz *= 2; ceil_loop(float); break;
+ case IM_BANDFMT_DPCOMPLEX: sz *= 2; ceil_loop(double); break;
+
+ default:
+ assert( 0 );
+ }
+}
+
+/* Ceil of image.
+ */
+int
+im_ceil( IMAGE *in, IMAGE *out )
+{
+ /* Check args.
+ */
+ if( in->Coding != IM_CODING_NONE ) {
+ im_error( "im_ceil", "%s", _( "not uncoded" ) );
+ return( -1 );
+ }
+
+ /* Is this one of the int types? Degenerate to im_copy() if it
+ * is.
+ */
+ if( im_isint( in ) )
+ return( im_copy( in, out ) );
+
+ /* Output type == input type.
+ */
+ if( im_cp_desc( out, in ) )
+ return( -1 );
+
+ /* Generate!
+ */
+ if( im_wrapone( in, out,
+ (im_wrapone_fn) ceil_gen, in, NULL ) )
+ return( -1 );
+
+ return( 0 );
+}
diff --git a/libvips/arithmetic/im_cmulnorm.c b/libvips/arithmetic/im_cmulnorm.c
new file mode 100644
index 00000000..22eefbb6
--- /dev/null
+++ b/libvips/arithmetic/im_cmulnorm.c
@@ -0,0 +1,75 @@
+/* @(#) Multiplies two complex images. complex output is normalised to 1
+ * @(#) Inputs can be complex double or complex float
+ * @(#) Result (double complex or float complex) depends on inputs
+ * @(#) Function im_cmulnorm() assumes that the both input files
+ * @(#) are either memory mapped or in a buffer.
+ * @(#) Images must have the same no of bands and must be complex
+ * @(#) No check for overflow is carried out.
+ * @(#)
+ * @(#) int im_cmulnorm(in1, in2, out)
+ * @(#) IMAGE *in1, *in2, *out;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ * @(#)
+ *
+ * Copyright: 1990, N. Dessipris.
+ *
+ * Author: Nicos Dessipris
+ * Written on: 02/05/1990
+ * Modified on:
+ * 15/4/97 JC
+ * - thrown away and redone in terms of im_multiply()
+ * 9/7/02 JC
+ * - im_sign() broken out, done in terms of that
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+
+#include
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+int
+im_cmulnorm( IMAGE *in1, IMAGE *in2, IMAGE *out )
+{
+ IMAGE *t1 = im_open_local( out, "im_cmulnorm:1", "p" );
+
+ if( !t1 || im_multiply( in1, in2, t1 ) || im_sign( t1, out ) )
+ return( -1 );
+
+ return( 0 );
+}
diff --git a/libvips/arithmetic/im_costra.c b/libvips/arithmetic/im_costra.c
new file mode 100644
index 00000000..abe022c4
--- /dev/null
+++ b/libvips/arithmetic/im_costra.c
@@ -0,0 +1,239 @@
+/* @(#) Find cos of any non-complex image. Output is always float for integer
+ * @(#) input and double for double input. All angles in degrees.
+ * @(#)
+ * @(#) int
+ * @(#) im_costra( in, out )
+ * @(#) IMAGE *in, *out;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ * @(#)
+ *
+ * Copyright: 1990, N. Dessipris, based on im_powtra()
+ * Author: Nicos Dessipris
+ * Written on: 02/05/1990
+ * Modified on:
+ * 5/5/93 JC
+ * - adapted from im_lintra to work with partial images
+ * - incorrect implementation of complex logs removed
+ * 1/7/93 JC
+ * - adapted for partial v2
+ * - ANSIfied
+ * 24/2/95 JC
+ * - im_logtra() adapted to make im_costra()
+ * - adapted for im_wrapone()
+ * 26/1/96 JC
+ * - im_acostra() added
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* Define what we do for each band element type. Non-complex input, any
+ * output.
+ */
+#define loop( IN, OUT )\
+ {\
+ IN *p = (IN *) in;\
+ OUT *q = (OUT *) out;\
+ \
+ for( x = 0; x < sz; x++ )\
+ q[x] = cos( IM_RAD( (double) p[x] ) );\
+ }
+
+/* cos a buffer of PELs.
+ */
+static void
+costra_gen( PEL *in, PEL *out, int width, IMAGE *im )
+{
+ int x;
+ int sz = width * im->Bands;
+
+ /* Switch for all input types.
+ */
+ switch( im->BandFmt ) {
+ case IM_BANDFMT_UCHAR: loop( unsigned char, float ); break;
+ case IM_BANDFMT_CHAR: loop( signed char, float ); break;
+ case IM_BANDFMT_USHORT: loop( unsigned short, float ); break;
+ case IM_BANDFMT_SHORT: loop( signed short, float ); break;
+ case IM_BANDFMT_UINT: loop( unsigned int, float ); break;
+ case IM_BANDFMT_INT: loop( signed int, float ); break;
+ case IM_BANDFMT_FLOAT: loop( float, float ); break;
+ case IM_BANDFMT_DOUBLE: loop( double, double ); break;
+
+ default:
+ assert( 0 );
+ }
+}
+
+/* Cos transform.
+ */
+int
+im_costra( IMAGE *in, IMAGE *out )
+{
+ /* Check args.
+ */
+ if( im_piocheck( in, out ) )
+ return( -1 );
+ if( in->Coding != IM_CODING_NONE ) {
+ im_error( "im_costra", "%s", _( "not uncoded" ) );
+ return( -1 );
+ }
+ if( im_iscomplex( in ) ) {
+ im_error( "im_costra", "%s", _( "bad input type" ) );
+ return( -1 );
+ }
+
+ /* Prepare output header.
+ */
+ if( im_cp_desc( out, in ) )
+ return( -1 );
+ switch( in->BandFmt ) {
+ case IM_BANDFMT_UCHAR:
+ case IM_BANDFMT_CHAR:
+ case IM_BANDFMT_USHORT:
+ case IM_BANDFMT_SHORT:
+ case IM_BANDFMT_UINT:
+ case IM_BANDFMT_INT:
+ out->Bbits = IM_BBITS_FLOAT;
+ out->BandFmt = IM_BANDFMT_FLOAT;
+ break;
+
+ case IM_BANDFMT_FLOAT:
+ case IM_BANDFMT_DOUBLE:
+ break;
+
+ default:
+ assert( 0 );
+ }
+
+ /* Generate!
+ */
+ if( im_wrapone( in, out, (im_wrapone_fn) costra_gen, in, NULL ) )
+ return( -1 );
+
+ return( 0 );
+}
+
+/* And acos().
+ */
+#define aloop( IN, OUT )\
+ {\
+ IN *p = (IN *) in;\
+ OUT *q = (OUT *) out;\
+ \
+ for( x = 0; x < sz; x++ )\
+ q[x] = IM_DEG( acos( (double) p[x] ) );\
+ }
+
+/* acos a buffer of PELs.
+ */
+static void
+acostra_gen( PEL *in, PEL *out, int width, IMAGE *im )
+{
+ int x;
+ int sz = width * im->Bands;
+
+ /* Switch for all input types.
+ */
+ switch( im->BandFmt ) {
+ case IM_BANDFMT_UCHAR: aloop( unsigned char, float ); break;
+ case IM_BANDFMT_CHAR: aloop( signed char, float ); break;
+ case IM_BANDFMT_USHORT: aloop( unsigned short, float ); break;
+ case IM_BANDFMT_SHORT: aloop( signed short, float ); break;
+ case IM_BANDFMT_UINT: aloop( unsigned int, float ); break;
+ case IM_BANDFMT_INT: aloop( signed int, float ); break;
+ case IM_BANDFMT_FLOAT: aloop( float, float ); break;
+ case IM_BANDFMT_DOUBLE: aloop( double, double ); break;
+
+ default:
+ assert( 0 );
+ }
+}
+
+/* Acos transform.
+ */
+int
+im_acostra( IMAGE *in, IMAGE *out )
+{
+ /* Check args.
+ */
+ if( im_piocheck( in, out ) )
+ return( -1 );
+ if( in->Coding != IM_CODING_NONE ) {
+ im_error( "im_acostra", "%s", _( "not uncoded" ) );
+ return( -1 );
+ }
+ if( im_iscomplex( in ) ) {
+ im_error( "im_acostra", "%s", _( "bad input type" ) );
+ return( -1 );
+ }
+
+ /* Prepare output header.
+ */
+ if( im_cp_desc( out, in ) )
+ return( -1 );
+ switch( in->BandFmt ) {
+ case IM_BANDFMT_UCHAR:
+ case IM_BANDFMT_CHAR:
+ case IM_BANDFMT_USHORT:
+ case IM_BANDFMT_SHORT:
+ case IM_BANDFMT_UINT:
+ case IM_BANDFMT_INT:
+ out->Bbits = IM_BBITS_FLOAT;
+ out->BandFmt = IM_BANDFMT_FLOAT;
+ break;
+
+ case IM_BANDFMT_FLOAT:
+ case IM_BANDFMT_DOUBLE:
+ break;
+
+ default:
+ assert( 0 );
+ }
+
+ /* Generate!
+ */
+ if( im_wrapone( in, out, (im_wrapone_fn) acostra_gen, in, NULL ) )
+ return( -1 );
+
+ return( 0 );
+}
diff --git a/libvips/arithmetic/im_cross_phase.c b/libvips/arithmetic/im_cross_phase.c
new file mode 100644
index 00000000..5aba17af
--- /dev/null
+++ b/libvips/arithmetic/im_cross_phase.c
@@ -0,0 +1,158 @@
+/* @(#) Find the phase of the cross power spectrum of two complex images,
+ * @(#) expressed as a complex image where the modulus of each pixel is
+ * @(#) one.
+ * @(#)
+ * @(#) I.E. find (a.b*)/|a.b*| where
+ * @(#) . represents complex multiplication
+ * @(#) * represents the complex conjugate
+ * @(#) || represents the complex modulus
+ * @(#)
+ * @(#) int im_cross_phase( IMAGE *a, IMAGE *b, IMAGE *out );
+ * @(#)
+ * @(#) All functions return 0 on success and -1 on error
+ * @(#)
+ *
+ * Copyright: 2008, Nottingham Trent University
+ *
+ * Author: Tom Vajzovic
+ * Written on: 2008-01-09
+ *
+ * 2008-02-04 tcv:
+ * - exp( i.th ) == cos(th)+i.sin(th) NOT sin(th)+i.cos(th)
+ * - add quadratic version (ifdef'd out ATM - still using trigonometric one)
+ *
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+
+/* There doesn't seem to be much difference in speed between these two methods (on an Athlon64),
+ * so I use the modulus argument version, since atan2() is in c89 but hypot() is c99.
+ *
+ * If you think that it might be faster on your platform, uncomment the following:
+ */
+#define USE_MODARG_DIV
+
+#ifdef USE_MODARG_DIV
+
+#define COMPLEX_PHASE_FN( TYPE, ABS ) \
+static void \
+complex_phase_ ## TYPE ( void *in1, void *in2, void *out, int n, void *im, void *unrequired ){ \
+ \
+ TYPE *X= (TYPE*) in1; \
+ TYPE *Y= (TYPE*) in2; \
+ TYPE *Z= (TYPE*) out; \
+ TYPE *Z_stop= Z + 2 * n * ((IMAGE*)im)-> Bands; \
+ \
+ for( ; Z < Z_stop; X+= 2, Y+= 2 ){ \
+ double arg= atan2( X[1], X[0] ) - atan2( Y[1], Y[0] ); \
+ *Z++= cos( arg ); \
+ *Z++= sin( arg ); \
+ } \
+}
+
+#else /* USE_MODARG_DIV */
+
+#define COMPLEX_PHASE_FN( TYPE, ABS ) \
+static void \
+complex_phase_ ## TYPE ( void *in1, void *in2, void *out, int n, void *im, void *unrequired ){ \
+ \
+ TYPE *X= (TYPE*) in1; \
+ TYPE *Y= (TYPE*) in2; \
+ TYPE *Z= (TYPE*) out; \
+ TYPE *Z_stop= Z + 2 * n * ((IMAGE*)im)-> Bands; \
+ \
+ for( ; Z < Z_stop; X+= 2, Y+= 2 ) \
+ \
+ if( ABS( Y[0] ) > ABS( Y[1] )){ \
+ double a= Y[1] / Y[0]; \
+ double b= Y[0] + Y[1] * a; \
+ double re= ( X[0] + X[1] * a ) / b; \
+ double im= ( X[1] - X[0] * a ) / b; \
+ double mod= im__hypot( re, im ); \
+ *Z++= re / mod; \
+ *Z++= im / mod; \
+ } \
+ else { \
+ double a= Y[0] / Y[1]; \
+ double b= Y[1] + Y[0] * a; \
+ double re= ( X[0] * a + X[1] ) / b; \
+ double im= ( X[1] * a - X[0] ) / b; \
+ double mod= im__hypot( re, im ); \
+ *Z++= re / mod; \
+ *Z++= im / mod; \
+ } \
+}
+
+#endif /* USE_MODARG_DIV */
+
+COMPLEX_PHASE_FN( float, fabsf )
+COMPLEX_PHASE_FN( double, fabs )
+
+int im_cross_phase( IMAGE *a, IMAGE *b, IMAGE *out ){
+#define FUNCTION_NAME "im_phase"
+
+ if( im_pincheck( a ) || im_pincheck( b ) || im_poutcheck( out ))
+ return -1;
+
+ if( a-> Xsize != b-> Xsize || a-> Ysize != b-> Ysize ){
+ im_error( FUNCTION_NAME, "not same size" );
+ return -1;
+ }
+ if( a-> Bands != b-> Bands ){
+ im_error( FUNCTION_NAME, "numbers of bands differ" );
+ return -1;
+ }
+ if( a-> Coding || b-> Coding ){
+ im_error( FUNCTION_NAME, "not uncoded" );
+ return -1;
+ }
+ if( a-> BandFmt != b-> BandFmt ){
+ im_error( FUNCTION_NAME, "formats differ" );
+ return -1;
+ }
+ if( IM_BANDFMT_COMPLEX != a-> BandFmt && IM_BANDFMT_DPCOMPLEX != a-> BandFmt ){
+ im_error( FUNCTION_NAME, "not complex format" );
+ return -1;
+ }
+ return im_cp_descv( out, a, b, NULL ) || im_wraptwo( a, b, out,
+ IM_BANDFMT_COMPLEX == a-> BandFmt ? complex_phase_float : complex_phase_double, a, NULL );
+}
diff --git a/libvips/arithmetic/im_deviate.c b/libvips/arithmetic/im_deviate.c
new file mode 100644
index 00000000..addb7097
--- /dev/null
+++ b/libvips/arithmetic/im_deviate.c
@@ -0,0 +1,226 @@
+/* @(#) Find the standard deviation of an image. Takes any non-complex image
+ * @(#) format, returns a double. Finds the deviation of all bands.
+ * @(#)
+ * @(#) int
+ * @(#) im_deviate( im, out )
+ * @(#) IMAGE *im;
+ * @(#) double *out;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error.
+ *
+ * Copyright: 1990, J. Cupitt
+ *
+ * Author: J. Cupitt
+ * Written on: 02/08/1990
+ * Modified on:
+ * 5/5/93 JC
+ * - now does partial images
+ * - less likely to overflow
+ * - adapted from im_avg
+ * 1/7/93 JC
+ * - adapted for partial v2
+ * - ANSIfied
+ * 21/2/95 JC
+ * - modernised again
+ * 11/5/95 JC
+ * - oops! return( NULL ) in im_avg(), instead of return( -1 )
+ * 20/6/95 JC
+ * - now returns double, not float
+ * 13/1/05
+ * - use 64 bit arithmetic
+ * 8/12/06
+ * - add liboil support
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#ifdef HAVE_LIBOIL
+#include
+#endif /*HAVE_LIBOIL*/
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* Start function: allocate space for a pair of doubles in which we can
+ * accumulate the sum and the sum of squares.
+ */
+static void *
+start_fn( IMAGE *out, void *a, void *b )
+{
+ double *tmp;
+
+ if( !(tmp = IM_ARRAY( out, 2, double )) )
+ return( NULL );
+ tmp[0] = 0.0;
+ tmp[1] = 0.0;
+
+ return( (void *) tmp );
+}
+
+/* Stop function. Add this little sum to the main sum.
+ */
+static int
+stop_fn( void *seq, void *a, void *b )
+{
+ double *tmp = (double *) seq;
+ double *sum = (double *) a;
+
+ sum[0] += tmp[0];
+ sum[1] += tmp[1];
+
+ return( 0 );
+}
+
+/* Loop over region, adding information to the appropriate fields of tmp.
+ */
+static int
+scan_fn( REGION *reg, void *seq, void *a, void *b )
+{
+ double *tmp = (double *) seq;
+ Rect *r = ®->valid;
+ IMAGE *im = reg->im;
+ int le = r->left;
+ int to = r->top;
+ int bo = IM_RECT_BOTTOM(r);
+ int sz = IM_REGION_N_ELEMENTS( reg );
+ double s = 0.0;
+ double s2 = 0.0;
+ int x, y;
+
+/* Sum pels in this section.
+ */
+#define loop(TYPE) \
+ { TYPE *p; \
+ \
+ for( y = to; y < bo; y++ ) { \
+ p = (TYPE *) IM_REGION_ADDR( reg, le, y ); \
+ \
+ for( x = 0; x < sz; x++ ) { \
+ TYPE v = p[x]; \
+ \
+ s += v; \
+ s2 += (double) v * (double) v; \
+ }\
+ }\
+ }
+
+ /* Now generate code for all types.
+ */
+ switch( im->BandFmt ) {
+ case IM_BANDFMT_UCHAR: loop(unsigned char); break;
+ case IM_BANDFMT_CHAR: loop(signed char); break;
+ case IM_BANDFMT_USHORT: loop(unsigned short); break;
+ case IM_BANDFMT_SHORT: loop(signed short); break;
+ case IM_BANDFMT_UINT: loop(unsigned int); break;
+ case IM_BANDFMT_INT: loop(signed int); break;
+ case IM_BANDFMT_FLOAT: loop(float); break;
+
+ case IM_BANDFMT_DOUBLE:
+#ifdef HAVE_LIBOIL
+ for( y = to; y < bo; y++ ) {
+ double *p = (double *) IM_REGION_ADDR( reg, le, y );
+ double t;
+ double t2;
+
+ oil_sum_f64( &t, p, sizeof( double ), sz );
+ oil_squaresum_f64( &t2, p, sz );
+
+ s += t;
+ s2 += t2;
+ }
+#else /*!HAVE_LIBOIL*/
+ loop(double);
+#endif /*HAVE_LIBOIL*/
+ break;
+
+ default:
+ assert( 0 );
+ }
+
+ /* Add to sum for this sequence.
+ */
+ tmp[0] += s;
+ tmp[1] += s2;
+
+ return( 0 );
+}
+
+/* Find the average of an image.
+ */
+int
+im_deviate( IMAGE *in, double *out )
+{
+ double sum[2] = { 0.0, 0.0 };
+ gint64 N;
+
+ /* Check our args.
+ */
+ if( im_pincheck( in ) )
+ return( -1 );
+ if( in->Coding != IM_CODING_NONE ) {
+ im_error( "im_deviate", "%s", _( "not uncoded" ) );
+ return( -1 );
+ }
+ if( im_iscomplex( in ) ) {
+ im_error( "im_deviate", "%s", _( "bad input type" ) );
+ return( -1 );
+ }
+
+ /* Loop over input, summing pixels.
+ */
+ if( im_iterate( in, start_fn, scan_fn, stop_fn, &sum, NULL ) )
+ return( -1 );
+
+ /*
+
+ NOTE: NR suggests a two-pass algorithm to minimise roundoff.
+ But that's too expensive for us :-( so do it the old one-pass
+ way.
+
+ */
+
+ /* Calculate and return deviation. Add a fabs to stop sqrt(<=0).
+ */
+ N = (gint64) in->Xsize * in->Ysize * in->Bands;
+ *out = sqrt( fabs( sum[1] - (sum[0] * sum[0] / N) ) / (N - 1) );
+
+ return( 0 );
+}
diff --git a/libvips/arithmetic/im_divide.c b/libvips/arithmetic/im_divide.c
new file mode 100644
index 00000000..c17755db
--- /dev/null
+++ b/libvips/arithmetic/im_divide.c
@@ -0,0 +1,234 @@
+/* @(#) Divide two images
+ * @(#) Images must have the same no of bands and can be of any type
+ * @(#) No check for overflow is carried out.
+ * @(#)
+ * @(#) int
+ * @(#) im_divide(in1, in2, out)
+ * @(#) IMAGE *in1, *in2, *out;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ * @(#)
+ *
+ * Copyright: 1990, N. Dessipris.
+ *
+ * Author: Nicos Dessipris
+ * Written on: 02/05/1990
+ * Modified on:
+ * 29/4/93 JC
+ * - now works for partial images
+ * 1/7/93 JC
+ * - adapted for partial v2
+ * - ANSIfied
+ * 19/10/93 JC
+ * - coredump-inducing bug in complex*complex fixed
+ * 13/12/93
+ * - char*short bug fixed
+ * 12/6/95 JC
+ * - new im_multiply adapted to make new im_divide
+ * 27/9/04
+ * - updated for 1 band $op n band image -> n band image case
+ * 8/12/06
+ * - add liboil support
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#ifdef HAVE_LIBOIL
+#include
+#endif /*HAVE_LIBOIL*/
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* Complex divide.
+ */
+#ifdef USE_MODARG_DIV
+/* This is going to be much slower */
+
+#define cloop(TYPE) \
+{ \
+ TYPE *X= (TYPE*) in[0]; \
+ TYPE *Y= (TYPE*) in[1]; \
+ TYPE *Z= (TYPE*) out; \
+ TYPE *Z_stop= Z + sz * 2; \
+ \
+ for( ; Z < Z_stop; X+= 2, Y+=2 ){ \
+ double arg= atan2( X[1], X[0] ) - atan2( Y[1], Y[0] ); \
+ double mod= hypot( X[1], X[0] ) / hypot( Y[1], Y[0] ); \
+ *Z++= mod * cos( arg ); \
+ *Z++= mod * sin( arg ); \
+ } \
+}
+
+#else /* USE_MODARG_DIV */
+
+#define cloop(TYPE) \
+{ \
+ TYPE *X= (TYPE*) in[0]; \
+ TYPE *Y= (TYPE*) in[1]; \
+ TYPE *Z= (TYPE*) out; \
+ TYPE *Z_stop= Z + sz * 2; \
+ \
+ for( ; Z < Z_stop; X+= 2, Y+=2 ) \
+ if( fabs( Y[0] ) > fabs( Y[1] )){ \
+ double a= Y[1] / Y[0]; \
+ double b= Y[0] + Y[1] * a; \
+ *Z++= ( X[0] + X[1] * a ) / b; \
+ *Z++= ( X[1] - X[0] * a ) / b; \
+ } \
+ else { \
+ double a= Y[0] / Y[1]; \
+ double b= Y[1] + Y[0] * a; \
+ *Z++= ( X[0] * a + X[1] ) / b; \
+ *Z++= ( X[1] * a - X[0] ) / b; \
+ } \
+}
+
+#endif /* USE_MODARG_DIV */
+
+/* Real divide.
+ */
+#define rloop(TYPE) \
+{\
+ TYPE *p1 = (TYPE *) in[0];\
+ TYPE *p2 = (TYPE *) in[1];\
+ TYPE *q = (TYPE *) out;\
+ \
+ for( x = 0; x < sz; x++ )\
+ q[x] = p1[x] / p2[x];\
+}
+
+static void
+divide_buffer( PEL **in, PEL *out, int width, IMAGE *im )
+{
+ int x;
+ int sz = width * im->Bands;
+
+ /* Divide all input types.
+ */
+ switch( im->BandFmt ) {
+ case IM_BANDFMT_CHAR: rloop( signed char ); break;
+ case IM_BANDFMT_UCHAR: rloop( unsigned char ); break;
+ case IM_BANDFMT_SHORT: rloop( signed short ); break;
+ case IM_BANDFMT_USHORT: rloop( unsigned short ); break;
+ case IM_BANDFMT_INT: rloop( signed int ); break;
+ case IM_BANDFMT_UINT: rloop( unsigned int ); break;
+
+ case IM_BANDFMT_FLOAT:
+#ifdef HAVE_LIBOIL
+ oil_divide_f32( (float *) out,
+ (float *) in[0], (float *) in[1], sz );
+#else /*!HAVE_LIBOIL*/
+ rloop( float );
+#endif /*HAVE_LIBOIL*/
+ break;
+
+ case IM_BANDFMT_DOUBLE: rloop( double ); break;
+ case IM_BANDFMT_COMPLEX: cloop( float ); break;
+ case IM_BANDFMT_DPCOMPLEX: cloop( double ); break;
+
+ default:
+ assert( 0 );
+ }
+}
+
+int
+im_divide( IMAGE *in1, IMAGE *in2, IMAGE *out )
+{
+ /* Basic checks.
+ */
+ if( im_piocheck( in1, out ) || im_pincheck( in2 ) )
+ return( -1 );
+ if( in1->Bands != in2->Bands &&
+ (in1->Bands != 1 && in2->Bands != 1) ) {
+ im_error( "im_divide", "%s", _( "not same number of bands" ) );
+ return( -1 );
+ }
+ if( in1->Coding != IM_CODING_NONE || in2->Coding != IM_CODING_NONE ) {
+ im_error( "im_divide", "%s", _( "not uncoded" ) );
+ return( -1 );
+ }
+ if( im_cp_descv( out, in1, in2, NULL ) )
+ return( -1 );
+
+ /* What number of bands will we write?
+ */
+ out->Bands = IM_MAX( in1->Bands, in2->Bands );
+
+ /* What output type will we write? float, double or complex.
+ */
+ if( im_iscomplex( in1 ) || im_iscomplex( in2 ) ) {
+ /* What kind of complex?
+ */
+ if( in1->BandFmt == IM_BANDFMT_DPCOMPLEX ||
+ in2->BandFmt == IM_BANDFMT_DPCOMPLEX )
+ /* Output will be DPCOMPLEX.
+ */
+ out->BandFmt = IM_BANDFMT_DPCOMPLEX;
+ else
+ out->BandFmt = IM_BANDFMT_COMPLEX;
+
+ }
+ else if( im_isfloat( in1 ) || im_isfloat( in2 ) ) {
+ /* What kind of float?
+ */
+ if( in1->BandFmt == IM_BANDFMT_DOUBLE ||
+ in2->BandFmt == IM_BANDFMT_DOUBLE )
+ out->BandFmt = IM_BANDFMT_DOUBLE;
+ else
+ out->BandFmt = IM_BANDFMT_FLOAT;
+ }
+ else {
+ /* An int type -- output must be just float.
+ */
+ out->BandFmt = IM_BANDFMT_FLOAT;
+ }
+
+ /* And process!
+ */
+ if( im__cast_and_call( in1, in2, out,
+ (im_wrapmany_fn) divide_buffer, NULL ) )
+ return( -1 );
+
+ /* Success!
+ */
+ return( 0 );
+}
diff --git a/libvips/arithmetic/im_expntra.c b/libvips/arithmetic/im_expntra.c
new file mode 100644
index 00000000..7a927c88
--- /dev/null
+++ b/libvips/arithmetic/im_expntra.c
@@ -0,0 +1,249 @@
+/* @(#) Calculates n^pel, with n as a parameter.
+ * @(#) If input is up to float, output is float, else input is the same as
+ * @(#) output. Does not work for complex input.
+ * @(#)
+ * @(#) int
+ * @(#) im_expntra( in, out, e )
+ * @(#) IMAGE *in, *out;
+ * @(#) double e;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ * @(#)
+ *
+ * Copyright: 1990, N. Dessipris
+ *
+ * Author: Nicos Dessipris
+ * Written on: 02/05/1990
+ * Modified on:
+ * 10/12/93 JC
+ * - now reports total number of x/0, rather than each one.
+ * 1/2/95 JC
+ * - rewritten for PIO with im_wrapone()
+ * - incorrect complex code removed
+ * - /0 reporting removed for ease of programming
+ * 8/5/95 JC
+ * - im_expntra() adapted to make this
+ * 15/4/97 JC
+ * - oops, return(0) missing
+ * - M_E removed, as not everywhere
+ * 6/7/98 JC
+ * - _vec version added
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* Parameters saved here.
+ */
+typedef struct {
+ int n; /* Number of bands of constants */
+ double *e; /* Exponent values, one per band */
+} ExpntraInfo;
+
+/* Define what we do for each band element type. Single constant.
+ */
+#define loop1(IN, OUT)\
+{\
+ IN *p = (IN *) in;\
+ OUT *q = (OUT *) out;\
+ \
+ for( x = 0; x < sz; x++ ) {\
+ double f = (double) p[x];\
+ \
+ if( e == 0.0 && f < 0.0 ) {\
+ /* Division by zero! Difficult to report tho'\
+ */\
+ q[x] = 0.0;\
+ }\
+ else\
+ q[x] = pow( e, f );\
+ }\
+}
+
+/* Expntra a buffer.
+ */
+static int
+expntra1_gen( PEL *in, PEL *out, int width, IMAGE *im, ExpntraInfo *inf )
+{
+ int sz = width * im->Bands;
+ double e = inf->e[0];
+ int x;
+
+ /* Expntra all non-complex input types.
+ */
+ switch( im->BandFmt ) {
+ case IM_BANDFMT_UCHAR: loop1(unsigned char, float); break;
+ case IM_BANDFMT_CHAR: loop1(signed char, float); break;
+ case IM_BANDFMT_USHORT: loop1(unsigned short, float); break;
+ case IM_BANDFMT_SHORT: loop1(signed short, float); break;
+ case IM_BANDFMT_UINT: loop1(unsigned int, float); break;
+ case IM_BANDFMT_INT: loop1(signed int, float); break;
+ case IM_BANDFMT_FLOAT: loop1(float, float); break;
+ case IM_BANDFMT_DOUBLE: loop1(double, double); break;
+
+ default:
+ assert( 0 );
+ }
+
+ return( 0 );
+}
+
+/* Define what we do for each band element type. One constant per band.
+ */
+#define loopn(IN, OUT)\
+{\
+ IN *p = (IN *) in;\
+ OUT *q = (OUT *) out;\
+ \
+ for( i = 0, x = 0; x < width; x++ )\
+ for( k = 0; k < im->Bands; k++, i++ ) {\
+ double e = inf->e[k];\
+ double f = (double) p[i];\
+ \
+ if( e == 0.0 && f < 0.0 ) {\
+ q[i] = 0.0;\
+ }\
+ else\
+ q[i] = pow( e, f );\
+ }\
+}
+
+/* Expntra a buffer.
+ */
+static int
+expntran_gen( PEL *in, PEL *out, int width, IMAGE *im, ExpntraInfo *inf )
+{
+ int x, k, i;
+
+ /* Expntra all non-complex input types.
+ */
+ switch( im->BandFmt ) {
+ case IM_BANDFMT_UCHAR: loopn(unsigned char, float); break;
+ case IM_BANDFMT_CHAR: loopn(signed char, float); break;
+ case IM_BANDFMT_USHORT: loopn(unsigned short, float); break;
+ case IM_BANDFMT_SHORT: loopn(signed short, float); break;
+ case IM_BANDFMT_UINT: loopn(unsigned int, float); break;
+ case IM_BANDFMT_INT: loopn(signed int, float); break;
+ case IM_BANDFMT_FLOAT: loopn(float, float); break;
+ case IM_BANDFMT_DOUBLE: loopn(double, double); break;
+
+ default:
+ assert( 0 );
+ }
+
+ return( 0 );
+}
+
+int
+im_expntra_vec( IMAGE *in, IMAGE *out, int n, double *e )
+{
+ ExpntraInfo *inf;
+ int i;
+
+ /* Check args.
+ */
+ if( in->Coding != IM_CODING_NONE ) {
+ im_error( "im_expntra_vec", "%s", _( "not uncoded" ) );
+ return( -1 );
+ }
+ if( im_iscomplex( in ) ) {
+ im_error( "im_expntra_vec", "%s", _( "not non-complex" ) );
+ return( -1 );
+ }
+ if( n != 1 && n != in->Bands ) {
+ im_error( "im_expntra_vec",
+ _( "not 1 or %d elements in vector" ), in->Bands );
+ return( -1 );
+ }
+
+ /* Prepare output header.
+ */
+ if( im_cp_desc( out, in ) )
+ return( -1 );
+ if( im_isint( in ) ) {
+ out->Bbits = IM_BBITS_FLOAT;
+ out->BandFmt = IM_BANDFMT_FLOAT;
+ }
+
+ /* Make space for a little buffer.
+ */
+ if( !(inf = IM_NEW( out, ExpntraInfo )) ||
+ !(inf->e = IM_ARRAY( out, n, double )) )
+ return( -1 );
+ for( i = 0; i < n; i++ )
+ inf->e[i] = e[i];
+ inf->n = n;
+
+ /* Generate!
+ */
+ if( n == 1 ) {
+ if( im_wrapone( in, out,
+ (im_wrapone_fn) expntra1_gen, in, inf ) )
+ return( -1 );
+ }
+ else {
+ if( im_wrapone( in, out,
+ (im_wrapone_fn) expntran_gen, in, inf ) )
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+int
+im_expntra( IMAGE *in, IMAGE *out, double e )
+{
+ return( im_expntra_vec( in, out, 1, &e ) );
+}
+
+/* Define im_exptra() and im_exp10tra() in terms of im_expntra().
+ */
+int
+im_exptra( IMAGE *in, IMAGE *out )
+{
+ return( im_expntra( in, out, 2.7182818284590452354 ) );
+}
+
+int
+im_exp10tra( IMAGE *in, IMAGE *out )
+{
+ return( im_expntra( in, out, 10.0 ) );
+}
diff --git a/libvips/arithmetic/im_fav4.c b/libvips/arithmetic/im_fav4.c
new file mode 100644
index 00000000..c3aa7246
--- /dev/null
+++ b/libvips/arithmetic/im_fav4.c
@@ -0,0 +1,95 @@
+/* @(#) Optimised 4 frame average
+Copyright (C) 1992, Kirk Martinez, History of Art Dept, Birkbeck College
+*/
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+#define ARGS "fav4: frame average 4 frames\nARGS: im1 im2 im3 im4 outfile"
+#define NFRAMES 4
+
+/* @(#) Optimised 4 frame average
+Copyright (C) 1992, Kirk Martinez, History of Art Dept, Birkbeck College
+CHAR images only!
+ARGS: array of 4 source images and output image
+*/
+int
+im_fav4( IMAGE **in, IMAGE *out)
+{
+ PEL *result, *buffer, *p1, *p2, *p3, *p4;
+ int x,y;
+ int linebytes, PICY;
+
+/* check IMAGEs parameters
+*/
+if(im_iocheck(in[1], out)) return(-1);
+
+/* BYTE images only!
+*/
+if( (in[0]->BandFmt != IM_BANDFMT_CHAR) && (in[0]->BandFmt != IM_BANDFMT_UCHAR)) return(-1);
+
+if ( im_cp_desc(out, in[1]) == -1) /* copy image descriptors */
+ return(-1);
+if ( im_setupout(out) == -1)
+ return(-1);
+
+linebytes = in[0]->Xsize * in[0]->Bands;
+PICY = in[0]->Ysize;
+buffer = (PEL*)im_malloc(NULL,linebytes);
+memset(buffer, 0, linebytes);
+
+ p1 = (PEL*)in[0]->data;
+ p2 = (PEL*)in[1]->data;
+ p3 = (PEL*)in[2]->data;
+ p4 = (PEL*)in[3]->data;
+
+for (y = 0; y < PICY; y++)
+ {
+ result = buffer;
+ /* average 4 pels with rounding, for whole line*/
+ for (x = 0; x < linebytes; x++) {
+ *result++ = (PEL)((int)((int)*p1++ + (int)*p2++ + (int)*p3++ + (int)*p4++ +2) >> 2);
+ }
+ im_writeline(y,out, buffer);
+ }
+im_free(buffer);
+return(0);
+}
+
diff --git a/libvips/arithmetic/im_floor.c b/libvips/arithmetic/im_floor.c
new file mode 100644
index 00000000..9ad229c6
--- /dev/null
+++ b/libvips/arithmetic/im_floor.c
@@ -0,0 +1,128 @@
+/* @(#) floor() an image ... no promotion, so output type == input type
+ * @(#)
+ * @(#) int
+ * @(#) im_floor( in, out )
+ * @(#) IMAGE *in, *out;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ * @(#)
+ *
+ * 20/6/02 JC
+ * - adapted from im_abs()
+ * 8/12/06
+ * - add liboil support
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#ifdef HAVE_LIBOIL
+#include
+#endif /*HAVE_LIBOIL*/
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+#define floor_loop(TYPE)\
+ {\
+ TYPE *p = (TYPE *) in;\
+ TYPE *q = (TYPE *) out;\
+ \
+ for( x = 0; x < sz; x++ )\
+ q[x] = floor( p[x] );\
+ }
+
+/* Ceil a buffer of PELs.
+ */
+static void
+floor_gen( PEL *in, PEL *out, int width, IMAGE *im )
+{
+ int x;
+ int sz = width * im->Bands;
+
+ switch( im->BandFmt ) {
+ case IM_BANDFMT_FLOAT:
+#ifdef HAVE_LIBOIL
+ oil_floor_f32( (float *) out, (float *) in, sz );
+#else /*!HAVE_LIBOIL*/
+ floor_loop(float);
+#endif /*HAVE_LIBOIL*/
+ break;
+
+ case IM_BANDFMT_DOUBLE: floor_loop(double); break;
+ case IM_BANDFMT_COMPLEX: sz *= 2; floor_loop(float); break;
+ case IM_BANDFMT_DPCOMPLEX: sz *= 2; floor_loop(double); break;
+
+ default:
+ assert( 0 );
+ }
+}
+
+/* Ceil of image.
+ */
+int
+im_floor( IMAGE *in, IMAGE *out )
+{
+ /* Check args.
+ */
+ if( in->Coding != IM_CODING_NONE ) {
+ im_error( "im_floor", "%s", _( "not uncoded" ) );
+ return( -1 );
+ }
+
+ /* Is this one of the int types? Degenerate to im_copy() if it
+ * is.
+ */
+ if( im_isint( in ) )
+ return( im_copy( in, out ) );
+
+ /* Output type == input type.
+ */
+ if( im_cp_desc( out, in ) )
+ return( -1 );
+
+ /* Generate!
+ */
+ if( im_wrapone( in, out,
+ (im_wrapone_fn) floor_gen, in, NULL ) )
+ return( -1 );
+
+ return( 0 );
+}
diff --git a/libvips/arithmetic/im_gadd.c b/libvips/arithmetic/im_gadd.c
new file mode 100644
index 00000000..5b35b666
--- /dev/null
+++ b/libvips/arithmetic/im_gadd.c
@@ -0,0 +1,127 @@
+/* @(#) Generalised addition of two vasari images using the routines
+ * @(#) im_gaddim or im_gfadd
+ * @(#) Convention to ease the complilation time.
+ * @(#) Function im_gadd() assumes that the both input files
+ * @(#) are either memory mapped or in a buffer.
+ * @(#) Images must have the same no of bands and must not be complex
+ * @(#) No check for overflow is carried out.
+ * @(#)
+ * @(#) int im_gadd(a, in1, b, in2, c, out)
+ * @(#) IMAGE *in1, *in2, *out;
+ * @(#) double a, b, c;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ * @(#)
+ *
+ * Copyright: 1990, N. Dessipris.
+ *
+ * Author: Nicos Dessipris
+ * Written on: 02/05/1990
+ * Modified on:
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+extern int im_gfadd();
+extern int im_gaddim();
+
+/* This function works on either mmaped files or on images in buffer
+ */
+
+int im_gadd(a, in1, b, in2, c, out)
+IMAGE *in1, *in2, *out;
+double a, b, c;
+{
+ int flagint = 0;
+ int flagfloat = 0;
+ int value = 0;
+
+ switch(in1->BandFmt) {
+ case IM_BANDFMT_UCHAR:
+ case IM_BANDFMT_CHAR:
+ case IM_BANDFMT_USHORT:
+ case IM_BANDFMT_SHORT:
+ case IM_BANDFMT_UINT:
+ case IM_BANDFMT_INT:
+ flagint = 1;
+ break;
+ case IM_BANDFMT_FLOAT:
+ case IM_BANDFMT_DOUBLE:
+ flagfloat = 1;
+ break;
+ default: im_error("im_gadd","%s", _("Unable to accept image1"));
+ return(-1);
+ }
+ switch(in2->BandFmt) {
+ case IM_BANDFMT_UCHAR:
+ case IM_BANDFMT_CHAR:
+ case IM_BANDFMT_USHORT:
+ case IM_BANDFMT_SHORT:
+ case IM_BANDFMT_UINT:
+ case IM_BANDFMT_INT:
+ flagint = 1;
+ break;
+ case IM_BANDFMT_FLOAT:
+ case IM_BANDFMT_DOUBLE:
+ flagfloat = 1;
+ break;
+ default: im_error("im_gadd","%s", _("Unable to accept image1"));
+ return(-1);
+ }
+ /* Select output routines */
+ if (flagfloat == 1)
+ {
+ value = im_gfadd(a, in1, b, in2, c, out);
+ if (value == -1)
+ return(-1);
+ }
+ else if (flagint == 1)
+ {
+ value = im_gaddim(a, in1, b, in2, c, out);
+ if (value == -1)
+ return(-1);
+ }
+ else
+ assert( 0 );
+
+ return(0);
+}
diff --git a/libvips/arithmetic/im_gaddim.c b/libvips/arithmetic/im_gaddim.c
new file mode 100644
index 00000000..a15dd911
--- /dev/null
+++ b/libvips/arithmetic/im_gaddim.c
@@ -0,0 +1,241 @@
+/* @(#) Generalised addition of two vasari images.
+ * @(#)Inputs, outputs are neither float nor double
+ * @(#) Result at each point is a*in1 + b*in2 + c
+ * @(#) Result depends on inputs, rounding is carried out;
+ * @(#) Function im_gaddim() assumes that the both input files
+ * @(#) are either memory mapped or in a buffer.
+ * @(#) Images must have the same no of bands and must not be complex
+ * @(#) No check for overflow is done;
+ * @(#)
+ * @(#) int im_gaddim(a, in1, b, in2, c, out)
+ * @(#) double a, b, c;
+ * @(#) IMAGE *in1, *in2, *out;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ * @(#)
+ *
+ * Copyright: 1990, N. Dessipris.
+ *
+ * Author: Nicos Dessipris
+ * Written on: 02/05/1990
+ * Modified on:
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* This function works on either mmaped files or on images in buffer
+ */
+
+/* uchar char ushort short uint int */
+static int array[6][6] = {
+/* uchar */ { 2, 3, 2, 3, 4, 5 },
+/* char */ { 3, 3, 3, 3, 5, 5 },
+/* ushort */ { 2, 3, 2, 3, 4, 5 },
+/* short */ { 3, 3, 3, 3, 5, 5 },
+/* uint */ { 4, 5, 4, 5, 4, 5 },
+/* int */ { 5, 5, 5, 5, 5, 5 }
+ };
+
+#define select_tmp2_for_out_int(OUT) \
+ case IM_BANDFMT_UCHAR: select_tmp1_for_out_int(unsigned char, OUT); break; \
+ case IM_BANDFMT_CHAR: select_tmp1_for_out_int(signed char, OUT); break; \
+ case IM_BANDFMT_USHORT: select_tmp1_for_out_int(unsigned short, OUT); break; \
+ case IM_BANDFMT_SHORT: select_tmp1_for_out_int(signed short, OUT); break; \
+ case IM_BANDFMT_UINT: select_tmp1_for_out_int(unsigned int, OUT); break; \
+ case IM_BANDFMT_INT: select_tmp1_for_out_int(signed int, OUT); break; \
+\
+ default: \
+ im_error("im_gaddim","Wrong tmp2 format(1)"); \
+ free( line); \
+ return(-1);
+
+#define select_tmp1_for_out_int(IN2, OUT) \
+ switch(tmp1->BandFmt) { \
+ case IM_BANDFMT_UINT: loop(unsigned int, IN2, OUT); break; \
+ case IM_BANDFMT_INT: loop(int, IN2, OUT); break; \
+ default: im_error("im_gaddim","Wrong tmp2 format(2)");\
+ free( line);\
+ return(-1); \
+ }
+
+#define select_tmp2_for_out_short(OUT) \
+ case IM_BANDFMT_UCHAR: select_tmp1_for_out_short(unsigned char, OUT); break; \
+ case IM_BANDFMT_CHAR: select_tmp1_for_out_short(signed char, OUT); break; \
+ case IM_BANDFMT_USHORT: select_tmp1_for_out_short(unsigned short, OUT); break; \
+ case IM_BANDFMT_SHORT: select_tmp1_for_out_short(signed short, OUT); break;
+#define select_tmp1_for_out_short(IN2, OUT) \
+ switch(tmp1->BandFmt) { \
+ case IM_BANDFMT_UCHAR: loop(unsigned char, IN2, OUT); break; \
+ case IM_BANDFMT_CHAR: loop(signed char, IN2, OUT); break; \
+ case IM_BANDFMT_USHORT: loop(unsigned short, IN2, OUT); break; \
+ case IM_BANDFMT_SHORT: loop(signed short, IN2, OUT); break; \
+ default: im_error("im_gaddim","Wrong image1 format(4)");\
+ free( line);\
+ return(-1); \
+ }
+
+
+
+int im_gaddim(a, in1, b, in2, c, out)
+IMAGE *in1, *in2, *out;
+double a, b, c;
+{
+ static int bb[] = { IM_BBITS_BYTE, IM_BBITS_BYTE, IM_BBITS_SHORT,
+ IM_BBITS_SHORT, IM_BBITS_INT, IM_BBITS_INT };
+ static int fmt[] = { IM_BANDFMT_UCHAR, IM_BANDFMT_CHAR,
+ IM_BANDFMT_USHORT, IM_BANDFMT_SHORT,
+ IM_BANDFMT_UINT, IM_BANDFMT_INT };
+ int y, x;
+ int first, second, result;
+ IMAGE *tmp1, *tmp2;
+ PEL *line;
+ int os; /* size of a line of output image */
+
+/* fd, data filename must have been set before the function is called
+ * Check whether they are set properly */
+ if ((im_iocheck(in1, out) == -1) || (im_iocheck(in2, out) == -1))
+ {
+ return(-1);
+ }
+/* Checks the arguments entered in in and prepares out */
+ if ( (in1->Xsize != in2->Xsize) || (in1->Ysize != in2->Ysize) ||
+ (in1->Bands != in2->Bands) || (in1->Coding != in2->Coding) )
+ { im_error("im_gaddim"," Input images differ"); return(-1); }
+ if (in1->Coding != IM_CODING_NONE)
+ { im_error("im_gaddim"," images must be uncoded"); return(-1);}
+
+ switch(in1->BandFmt) {
+ case IM_BANDFMT_UCHAR: first = 0; break;
+ case IM_BANDFMT_CHAR: first = 1; break;
+ case IM_BANDFMT_USHORT: first = 2; break;
+ case IM_BANDFMT_SHORT: first = 3; break;
+ case IM_BANDFMT_UINT: first = 4; break;
+ case IM_BANDFMT_INT: first = 5; break;
+ default: im_error("im_gaddim"," Unable to accept image1");
+ return(-1);
+ }
+ switch(in2->BandFmt) {
+ case IM_BANDFMT_UCHAR: second = 0; break;
+ case IM_BANDFMT_CHAR: second = 1; break;
+ case IM_BANDFMT_USHORT: second = 2; break;
+ case IM_BANDFMT_SHORT: second = 3; break;
+ case IM_BANDFMT_UINT: second = 4; break;
+ case IM_BANDFMT_INT: second = 5; break;
+ default: im_error("im_gaddim"," Unable to accept image2");
+ return(-1);
+ }
+/* Define the output */
+ result = array[first][second];
+
+/* Prepare the output header */
+ if ( im_cp_desc(out, in1) == -1)
+ { im_error("im_gaddim"," im_cp_desc failed"); return(-1); }
+ out->Bbits = bb[result];
+ out->BandFmt = fmt[result];
+
+ if( im_setupout(out) == -1)
+ { im_error("im_gaddim"," im_setupout failed"); return(-1); }
+
+/* Order in1 and in2 */
+ if ( first >= second )
+ { tmp1 = in1; tmp2 = in2; }
+ else
+ { tmp1 = in2; tmp2 = in1; }
+
+/* Define what we do for each band element type. */
+
+#define loop(IN1, IN2, OUT) \
+ { IN1 *input1 = (IN1 *) tmp1->data; \
+ IN2 *input2 = (IN2 *) tmp2->data; \
+ \
+ for (y=0; y Ysize; y++) {\
+ OUT *cpline = (OUT*)line; \
+ for (x=0; xXsize * out->Bands;
+ line = (PEL *) calloc ( (unsigned)os, sizeof(double) );
+ if (line == NULL)
+ {
+ im_error("im_gaddim"," Unable to calloc");
+ return(-1);
+ }
+
+ switch (out->BandFmt) {
+ case IM_BANDFMT_INT:
+ switch (tmp2->BandFmt) {
+ select_tmp2_for_out_int(int);
+ }
+ break;
+
+ case IM_BANDFMT_UINT:
+ switch (tmp2->BandFmt) {
+ select_tmp2_for_out_int(unsigned int);
+ }
+ break;
+ case IM_BANDFMT_SHORT:
+ switch (tmp2->BandFmt) {
+ select_tmp2_for_out_short(short);
+ }
+ break;
+ case IM_BANDFMT_USHORT:
+ switch (tmp2->BandFmt) {
+ select_tmp2_for_out_short(unsigned short);
+ }
+ break;
+ default:
+ im_error("im_gaddim"," Impossible output state");
+ free( line);
+ return(-1);
+ }
+
+ free( line);
+
+ return(0);
+}
diff --git a/libvips/arithmetic/im_gfadd.c b/libvips/arithmetic/im_gfadd.c
new file mode 100644
index 00000000..24fd7bcb
--- /dev/null
+++ b/libvips/arithmetic/im_gfadd.c
@@ -0,0 +1,351 @@
+/* @(#) Generalised addition of two vasari images. Result (double or float)
+ * @(#)depends on inputs
+ * @(#) Function im_gfadd() assumes that the both input files
+ * @(#) are either memory mapped or in a buffer.
+ * @(#) Images must have the same no of bands and can be of any type
+ * @(#) No check for overflow is carried out. If in doubt use im_clip2...
+ * @(#) Result at eachpoint is a*in1 + b*in2 + c
+ * @(#)
+ * @(#) int im_gfadd(a, in1, b, in2, c, out)
+ * @(#) double a, b, c;
+ * @(#) IMAGE *in1, *in2, *out;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ * @(#)
+ *
+ * Copyright: 1990, N. Dessipris.
+ *
+ * Author: Nicos Dessipris
+ * Written on: 02/05/1990
+ * Modified on:
+ * 15/6/93 J.Cupitt
+ * - externs removed
+ * - casts added to please ANSI C
+ * - includes rationalised
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* uchar char ushort short uint int float double */
+static int array[8][8] = {
+/* uchar */ { 0, 0, 0, 0, 0, 0, 0, 1 },
+/* char */ { 0, 0, 0, 0, 0, 0, 0, 1 },
+/* ushort */ { 0, 0, 0, 0, 0, 0, 0, 1 },
+/* short */ { 0, 0, 0, 0, 0, 0, 0, 1 },
+/* uint */ { 0, 0, 0, 0, 0, 0, 0, 1 },
+/* int */ { 0, 0, 0, 0, 0, 0, 0, 1 },
+/* float */ { 0, 0, 0, 0, 0, 0, 0, 1 },
+/* double */ { 1, 1, 1, 1, 1, 1, 1, 1 }
+ };
+
+#define select_outdouble(IN2, OUT)\
+ switch(tmp1->BandFmt) {\
+ case IM_BANDFMT_DOUBLE: loop(double, IN2, OUT); break;\
+ default: im_error("im_gfadd","Wrong tmp1 format(d)");\
+ free( line); return( -1 );\
+ }
+
+#define outfloat_2uchar(IN2, OUT)\
+ case IM_BANDFMT_UCHAR: loop(unsigned char, IN2, OUT); break;\
+ case IM_BANDFMT_CHAR: loop(signed char, IN2, OUT); break;\
+ case IM_BANDFMT_USHORT: loop(unsigned short, IN2, OUT); break;\
+ case IM_BANDFMT_SHORT: loop(signed short, IN2, OUT); break;\
+ case IM_BANDFMT_UINT: loop(unsigned int, IN2, OUT); break;\
+ case IM_BANDFMT_INT: loop(signed int, IN2, OUT); break;\
+ case IM_BANDFMT_FLOAT: loop(float, IN2, OUT); break;
+
+#define outfloat_2char(IN2, OUT)\
+ case IM_BANDFMT_CHAR: loop(signed char, IN2, OUT); break;\
+ case IM_BANDFMT_USHORT: loop(unsigned short, IN2, OUT); break;\
+ case IM_BANDFMT_SHORT: loop(signed short, IN2, OUT); break;\
+ case IM_BANDFMT_UINT: loop(unsigned int, IN2, OUT); break;\
+ case IM_BANDFMT_INT: loop(signed int, IN2, OUT); break;\
+ case IM_BANDFMT_FLOAT: loop(float, IN2, OUT); break;
+
+#define outfloat_2ushort(IN2, OUT)\
+ case IM_BANDFMT_USHORT: loop(unsigned short, IN2, OUT); break;\
+ case IM_BANDFMT_SHORT: loop(signed short, IN2, OUT); break;\
+ case IM_BANDFMT_UINT: loop(unsigned int, IN2, OUT); break;\
+ case IM_BANDFMT_INT: loop(signed int, IN2, OUT); break;\
+ case IM_BANDFMT_FLOAT: loop(float, IN2, OUT); break;
+
+#define outfloat_2short(IN2, OUT)\
+ case IM_BANDFMT_SHORT: loop(signed short, IN2, OUT); break;\
+ case IM_BANDFMT_UINT: loop(unsigned int, IN2, OUT); break;\
+ case IM_BANDFMT_INT: loop(signed int, IN2, OUT); break;\
+ case IM_BANDFMT_FLOAT: loop(float, IN2, OUT); break;
+
+#define outfloat_2uint(IN2, OUT)\
+ case IM_BANDFMT_UINT: loop(unsigned int, IN2, OUT); break;\
+ case IM_BANDFMT_INT: loop(signed int, IN2, OUT); break;\
+ case IM_BANDFMT_FLOAT: loop(float, IN2, OUT); break;
+
+#define outfloat_2int(IN2, OUT)\
+ case IM_BANDFMT_INT: loop(signed int, IN2, OUT); break;\
+ case IM_BANDFMT_FLOAT: loop(float, IN2, OUT); break;
+
+#define outfloat_2float(IN2, OUT)\
+ case IM_BANDFMT_FLOAT: loop(float, IN2, OUT); break;
+
+int im_gfadd(a, in1, b, in2, c, out)
+double a, b, c;
+IMAGE *in1, *in2, *out;
+{
+ static int bb[] = { IM_BBITS_FLOAT, IM_BBITS_DOUBLE };
+ static int fmt[] = { IM_BANDFMT_FLOAT, IM_BANDFMT_DOUBLE };
+ int y, x;
+ int first, second, result;
+ IMAGE *tmp1, *tmp2;
+ PEL *line;
+ int os; /* size of a line of output image */
+
+/* fd, data filename must have been set before the function is called
+ * Check whether they are set properly */
+ if ((im_iocheck(in1, out) == -1) || (im_iocheck(in2, out) == -1))
+ { im_error("im_gfadd"," im_iocheck failed"); return( -1 ); }
+/* Checks the arguments entered in in and prepares out */
+ if ( (in1->Xsize != in2->Xsize) || (in1->Ysize != in2->Ysize) ||
+ (in1->Bands != in2->Bands) || (in1->Coding != in2->Coding) )
+ { im_error("im_gfadd"," Input images differ"); return( -1 );}
+ if (in1->Coding != IM_CODING_NONE)
+ { im_error("im_gfadd"," images are coded"); return( -1 ); }
+
+ switch(in1->BandFmt) {
+ case IM_BANDFMT_UCHAR: first = 0; break;
+ case IM_BANDFMT_CHAR: first = 1; break;
+ case IM_BANDFMT_USHORT: first = 2; break;
+ case IM_BANDFMT_SHORT: first = 3; break;
+ case IM_BANDFMT_UINT: first = 4; break;
+ case IM_BANDFMT_INT: first = 5; break;
+ case IM_BANDFMT_FLOAT: first = 6; break;
+ case IM_BANDFMT_DOUBLE: first = 7; break;
+ default: im_error("im_gfadd"," unable to accept image1");
+ return( -1 );
+ }
+ switch(in2->BandFmt) {
+ case IM_BANDFMT_UCHAR: second = 0; break;
+ case IM_BANDFMT_CHAR: second = 1; break;
+ case IM_BANDFMT_USHORT: second = 2; break;
+ case IM_BANDFMT_SHORT: second = 3; break;
+ case IM_BANDFMT_UINT: second = 4; break;
+ case IM_BANDFMT_INT: second = 5; break;
+ case IM_BANDFMT_FLOAT: second = 6; break;
+ case IM_BANDFMT_DOUBLE: second = 7; break;
+ default: im_error("im_gfadd"," unable to accept image2");
+ return( -1 );
+ }
+/* Define the output */
+ result = array[first][second];
+/* Prepare output */
+ if ( im_cp_desc(out, in1) == -1)
+ { im_error("im_gfadd"," im_cp_desc failed"); return( -1 ); }
+ out->Bbits = bb[result];
+ out->BandFmt = fmt[result];
+ if( im_setupout(out) == -1)
+ { im_error("im_gfadd"," im_setupout failed"); return( -1 ); }
+
+/* Order in1 and in2 */
+ if ( first >= second )
+ { tmp1 = in1; tmp2 = in2; }
+ else
+ { tmp1 = in2; tmp2 = in1; }
+
+/* Define what we do for each band element type. */
+
+#define loop(IN1, IN2, OUT)\
+ { IN1 *input1 = (IN1 *) tmp1->data;\
+ IN2 *input2 = (IN2 *) tmp2->data;\
+ \
+ for (y=0; y Ysize; y++) {\
+ OUT *cpline = (OUT*)line;\
+ for (x=0; xXsize * out->Bands;
+ line = (PEL *) calloc ( (unsigned)os, sizeof(double) );
+ if (line == NULL)
+ { im_error("im_gfadd"," unable to calloc"); return( -1 ); }
+
+ switch (out->BandFmt) {
+ case IM_BANDFMT_DOUBLE:
+ switch (tmp2->BandFmt) {
+ case IM_BANDFMT_UCHAR:
+ select_outdouble(unsigned char, double);
+ break;
+
+ case IM_BANDFMT_CHAR:
+ select_outdouble(signed char, double);
+ break;
+
+ case IM_BANDFMT_USHORT:
+ select_outdouble(unsigned short, double);
+ break;
+
+ case IM_BANDFMT_SHORT:
+ select_outdouble(signed short, double);
+ break;
+
+ case IM_BANDFMT_UINT:
+ select_outdouble(unsigned int, double);
+ break;
+
+ case IM_BANDFMT_INT:
+ select_outdouble(signed int, double);
+ break;
+
+ case IM_BANDFMT_FLOAT:
+ select_outdouble(float, double);
+ break;
+
+ case IM_BANDFMT_DOUBLE:
+ select_outdouble(double, double);
+ break;
+
+ default:
+ im_error("im_gfadd","Wrong tmp2 format(d)");
+ free( line );
+ return( -1 );
+ }
+
+ break;
+
+ case IM_BANDFMT_FLOAT :
+ switch (tmp2->BandFmt) {
+ case IM_BANDFMT_UCHAR:
+ switch (tmp1->BandFmt) {
+ outfloat_2uchar(unsigned char, float);
+
+ default:
+ im_error("im_gfadd"," Error (a)");
+ free( line );
+ return( -1 );
+ }
+ break;
+
+ case IM_BANDFMT_CHAR:
+ switch (tmp1->BandFmt) {
+ outfloat_2char(signed char, float);
+
+ default:
+ im_error("im_gfadd"," Error (b)");
+ free( line); return( -1 );
+ }
+ break;
+
+ case IM_BANDFMT_USHORT:
+ switch (tmp1->BandFmt) {
+ outfloat_2ushort(unsigned short, float);
+
+ default:
+ im_error("im_gfadd"," Error (c)");
+ free( line); return( -1 );
+ }
+ break;
+
+ case IM_BANDFMT_SHORT:
+ switch (tmp1->BandFmt) {
+ outfloat_2short(signed short, float);
+
+ default:
+ im_error("im_gfadd"," Error (d)");
+ free( line); return( -1 );
+ }
+ break;
+
+ case IM_BANDFMT_UINT:
+ switch (tmp1->BandFmt) {
+ outfloat_2uint(unsigned int, float);
+
+ default:
+ im_error("im_gfadd"," Error (e)");
+ free( line); return( -1 );
+ }
+ break;
+
+ case IM_BANDFMT_INT:
+ switch (tmp1->BandFmt) {
+ outfloat_2int(signed int, float);
+
+ default:
+ im_error("im_gfadd"," Error (f)");
+ free( line );
+ return( -1 );
+ }
+ break;
+
+ case IM_BANDFMT_FLOAT:
+ switch (tmp1->BandFmt) {
+ outfloat_2float(float, float);
+
+ default:
+ im_error("im_gfadd"," Error (g)");
+ free( line );
+ return( -1 );
+ }
+ break;
+
+ default:
+ im_error("im_gfadd"," Wrong tmp2 format(f)");
+ free( line );
+ return( -1 );
+ }
+
+ break;
+
+ default:
+ im_error("im_gfadd"," Impossible output state");
+ free( line );
+ return( -1 );
+ }
+
+ free( line );
+
+ return( 0 );
+}
diff --git a/libvips/arithmetic/im_invert.c b/libvips/arithmetic/im_invert.c
new file mode 100644
index 00000000..d660b173
--- /dev/null
+++ b/libvips/arithmetic/im_invert.c
@@ -0,0 +1,151 @@
+/* @(#) Invert a UCHAR image. Very simple new-style VIPS routine. See
+ * @(#) im_exptra() for the next level of complexity. This function is not
+ * @(#) as quick as it could be - it is intended to be an example rather than
+ * @(#) to be useful. This should really be written with im_wrapone().
+ * @(#)
+ * @(#) int
+ * @(#) im_invert( IMAGE *in, IMAGE *out )
+ * @(#)
+ * @(#) All functions return 0 on success and -1 on error
+ * @(#)
+ *
+ * Copyright: 1990, N. Dessipris.
+ *
+ * Author: Nicos Dessipris
+ * Written on: 12/02/1990
+ * Modified on :
+ * 7/7/93 JC
+ * - memory leaks fixed
+ * - adapted for partial v2
+ * - ANSIfied
+ * 22/2/95 JC
+ * - tidied up again
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* Invert a REGION. We are given the REGION we should write to, the REGION we
+ * should use for input, and the IMAGE we are processing. On entry to
+ * invert_gen(), or points to the memory we should write to and ir is blank.
+ */
+static int
+invert_gen( REGION *or, void *seq, void *a, void *b )
+{
+ REGION *ir = (REGION *) seq;
+
+ /* Left, right, top and bottom for the output region.
+ */
+ int le = or->valid.left;
+ int to = or->valid.top;
+ int bo = IM_RECT_BOTTOM( &or->valid );
+
+ int x, y;
+
+ /* Ask for the section of the input image we need to produce this
+ * section of the output image.
+ */
+ if( im_prepare( ir, &or->valid ) )
+ return( -1 );
+
+ /* Loop over output, writing input.
+ */
+ for( y = to; y < bo; y++ ) {
+ /* Point p and q at the start of the line of pels we must
+ * process this loop.
+ */
+ PEL *p = (PEL *) IM_REGION_ADDR( ir, le, y );
+ PEL *q = (PEL *) IM_REGION_ADDR( or, le, y );
+
+ /* Loop along the line, processing pels.
+ * IM_REGION_N_ELEMENTS(region) gives
+ * the number of band elements across a region. By looping to
+ * IM_REGION_N_ELEMENTS() rather than ir->valid.width, we work
+ * for any number of bands.
+ */
+ for( x = 0; x < IM_REGION_N_ELEMENTS( or ); x++ )
+ q[x] = 255 - p[x];
+ }
+
+ return( 0 );
+}
+
+/* Invert IMAGE in to IMAGE out. Any number of bands, unsigned char pels
+ * only. See im_exptra() for an example of a VIPS function which can process
+ * any input image type.
+ */
+int
+im_invert( IMAGE *in, IMAGE *out )
+{
+ /* Check args.
+ */
+ if( in->Coding != IM_CODING_NONE ) {
+ im_error( "im_invert", "%s", _( "not uncoded" ) );
+ return( -1 );
+ }
+ if( in->BandFmt != IM_BANDFMT_UCHAR ) {
+ im_error( "im_invert", "%s", _( "not UCHAR" ) );
+ return( -1 );
+ }
+ if( im_piocheck( in, out ) )
+ return( -1 );
+
+ /* Prepare the output header.
+ */
+ if( im_cp_desc( out, in ) )
+ return( -1 );
+
+ /* Set demand hints. Like most one-to-one operations, we work best
+ * with long, thin strips.
+ */
+ if( im_demand_hint( out, IM_THINSTRIP, in, NULL ) )
+ return( -1 );
+
+ /* Generate into out. im_start_one() and im_stop_one() are simple
+ * convenience functions provided by VIPS which do the necessary
+ * region creation and destruction for one-image-in
+ * style functions. See im_add(), im_start_many() and im_stop_many()
+ * for convenience functions for multiple inputs.
+ */
+ if( im_generate( out,
+ im_start_one, invert_gen, im_stop_one, in, NULL ) )
+ return( -1 );
+
+ return( 0 );
+}
diff --git a/libvips/arithmetic/im_linreg.c b/libvips/arithmetic/im_linreg.c
new file mode 100644
index 00000000..bf6aba26
--- /dev/null
+++ b/libvips/arithmetic/im_linreg.c
@@ -0,0 +1,433 @@
+/* @(#) Function to find perform pixelwise linear regression on an array of
+ * @(#) single band images.
+ * @(#)
+ * @(#) int im_linreg(
+ * @(#) IMAGE **ins,
+ * @(#) IMAGE *out,
+ * @(#) double *xs
+ * @(#) );
+ * @(#)
+ *
+ * Copyright: 2006, The Nottingham Trent University
+ *
+ * Author: Tom Vajzovic
+ *
+ * Written on: 2006-12-26
+ *
+ * 12/5/09
+ * - make x_anal() static, fix some signed/unsigned warnings
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+
+/** HEADERS **/
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /* HAVE_CONFIG_H */
+#include
+
+#include
+#include
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC */
+
+
+/** TYPES **/
+
+typedef struct {
+
+ unsigned int n;
+ double *xs;
+ double *difs;
+ double mean;
+ double nsig2;
+ double err_term;
+
+} x_set;
+
+#define LINREG_SEQ( TYPE ) typedef struct { \
+ REGION **regs; \
+ TYPE **ptrs; \
+ size_t *skips; \
+} linreg_seq_ ## TYPE
+
+LINREG_SEQ( gint8 );
+LINREG_SEQ( guint8 );
+LINREG_SEQ( gint16 );
+LINREG_SEQ( guint16 );
+LINREG_SEQ( gint32 );
+LINREG_SEQ( guint32 );
+LINREG_SEQ( float );
+LINREG_SEQ( double );
+
+
+/** LOCAL FUNCTION DECLARATIONS **/
+
+static x_set *x_anal( IMAGE *im, double *xs, unsigned int n );
+
+#define LINREG_START_DECL( TYPE ) static void * linreg_start_ ## TYPE( IMAGE *, void *, void * );
+#define LINREG_GEN_DECL( TYPE ) static int linreg_gen_ ## TYPE( REGION *, void *, void *, void * );
+#define LINREG_STOP_DECL( TYPE ) static int linreg_stop_ ## TYPE( void *, void *, void * );
+#define INCR_ALL_DECL( TYPE ) static void incr_all_ ## TYPE( TYPE **ptrs, unsigned int n )
+#define SKIP_ALL_DECL( TYPE ) static void skip_all_ ## TYPE( TYPE **ptrs, size_t *skips, unsigned int n )
+
+LINREG_START_DECL( gint8 );
+LINREG_START_DECL( guint8 );
+LINREG_START_DECL( gint16 );
+LINREG_START_DECL( guint16 );
+LINREG_START_DECL( gint32 );
+LINREG_START_DECL( guint32 );
+LINREG_START_DECL( float );
+LINREG_START_DECL( double );
+
+LINREG_GEN_DECL( gint8 );
+LINREG_GEN_DECL( guint8 );
+LINREG_GEN_DECL( gint16 );
+LINREG_GEN_DECL( guint16 );
+LINREG_GEN_DECL( gint32 );
+LINREG_GEN_DECL( guint32 );
+LINREG_GEN_DECL( float );
+LINREG_GEN_DECL( double );
+
+LINREG_STOP_DECL( gint8 );
+LINREG_STOP_DECL( guint8 );
+LINREG_STOP_DECL( gint16 );
+LINREG_STOP_DECL( guint16 );
+LINREG_STOP_DECL( gint32 );
+LINREG_STOP_DECL( guint32 );
+LINREG_STOP_DECL( float );
+LINREG_STOP_DECL( double );
+
+INCR_ALL_DECL( gint8 );
+INCR_ALL_DECL( guint8 );
+INCR_ALL_DECL( gint16 );
+INCR_ALL_DECL( guint16 );
+INCR_ALL_DECL( gint32 );
+INCR_ALL_DECL( guint32 );
+INCR_ALL_DECL( float );
+INCR_ALL_DECL( double );
+
+SKIP_ALL_DECL( gint8 );
+SKIP_ALL_DECL( guint8 );
+SKIP_ALL_DECL( gint16 );
+SKIP_ALL_DECL( guint16 );
+SKIP_ALL_DECL( gint32 );
+SKIP_ALL_DECL( guint32 );
+SKIP_ALL_DECL( float );
+SKIP_ALL_DECL( double );
+
+
+/** EXPORTED FUNCTION DEFINITION **/
+
+int im_linreg( IMAGE **ins, IMAGE *out, double *xs ){
+#define FUNCTION_NAME "im_linreg"
+ int n;
+ x_set *x_vals;
+
+ if( im_poutcheck( out ) )
+ return( -1 );
+
+ for( n= 0; ins[ n ]; ++n ){
+/*
+ if( ! isfinite( xs[ n ] ) ){
+ im_error( FUNCTION_NAME, "invalid argument" );
+ return( -1 );
+ }
+*/
+ if( im_pincheck( ins[ n ] ) )
+ return( -1 );
+
+ if( 1 != ins[ n ]-> Bands ){
+ im_error( FUNCTION_NAME, "image is not single band" );
+ return( -1 );
+ }
+ if( ins[ n ]-> Coding ){
+ im_error( FUNCTION_NAME, "image is not uncoded" );
+ return( -1 );
+ }
+ if( n ){
+ if( ins[ n ]-> BandFmt != ins[ 0 ]-> BandFmt ){
+ im_error( FUNCTION_NAME, "image band formats differ" );
+ return( -1 );
+ }
+ }
+ else {
+ if( ! im_isscalar( ins[ 0 ] ) ){
+ im_error( FUNCTION_NAME, "image has non-scalar band format" );
+ return( -1 );
+ }
+ }
+ if( n && ( ins[ n ]-> Xsize != ins[ 0 ]-> Xsize
+ || ins[ n ]-> Ysize != ins[ 0 ]-> Ysize ) ){
+
+ im_error( FUNCTION_NAME, "image sizes differ" );
+ return( -1 );
+ }
+ }
+ if( n < 3 ){
+ im_error( FUNCTION_NAME, "not enough input images" );
+ return( -1 );
+ }
+ if( im_cp_desc_array( out, ins ) )
+ return( -1 );
+
+ out-> Bands= 7;
+ out-> BandFmt= IM_BANDFMT_DOUBLE;
+ out-> Bbits= IM_BBITS_DOUBLE;
+ out-> Type= 0;
+
+ if( im_demand_hint_array( out, IM_THINSTRIP, ins ) )
+ return( -1 );
+
+ x_vals= x_anal( out, xs, n );
+
+ if( ! x_vals )
+ return( -1 );
+
+ switch( ins[ 0 ]-> BandFmt ){
+#define LINREG_RET( TYPE ) return im_generate( out, linreg_start_ ## TYPE, linreg_gen_ ## TYPE, linreg_stop_ ## TYPE, ins, x_vals )
+
+ case IM_BANDFMT_CHAR:
+ LINREG_RET( gint8 );
+
+ case IM_BANDFMT_UCHAR:
+ LINREG_RET( guint8 );
+
+ case IM_BANDFMT_SHORT:
+ LINREG_RET( gint16 );
+
+ case IM_BANDFMT_USHORT:
+ LINREG_RET( guint16 );
+
+ case IM_BANDFMT_INT:
+ LINREG_RET( gint32 );
+
+ case IM_BANDFMT_UINT:
+ LINREG_RET( guint32 );
+
+ case IM_BANDFMT_FLOAT:
+ LINREG_RET( float );
+
+ case IM_BANDFMT_DOUBLE:
+ LINREG_RET( double );
+
+ default: /* keep -Wall happy */
+ return( -1 );
+ }
+#undef FUNCTION_NAME
+}
+
+
+/** LOCAL FUNCTION DECLARATIONS **/
+
+static x_set *x_anal( IMAGE *im, double *xs, unsigned int n ){
+ unsigned int i;
+
+ x_set *x_vals= IM_NEW( im, x_set );
+
+ if( ! x_vals )
+ return( NULL );
+
+ x_vals-> xs= IM_ARRAY( im, 2 * n, double );
+
+ if( ! x_vals-> xs )
+ return( NULL );
+
+ x_vals-> difs= x_vals-> xs + n;
+ x_vals-> n= n;
+ x_vals-> mean= 0.0;
+
+ for( i= 0; i < n; ++i ){
+ x_vals-> xs[ i ]= xs[ i ];
+ x_vals-> mean+= xs[ i ];
+ }
+ x_vals-> mean/= n;
+ x_vals-> nsig2= 0.0;
+
+ for( i= 0; i < n; ++i ){
+ x_vals-> difs[ i ]= xs[ i ] - x_vals-> mean;
+ x_vals-> nsig2+= x_vals-> difs[ i ] * x_vals-> difs[ i ];
+ }
+ x_vals-> err_term= ( 1.0 / (double) n ) + ( ( x_vals-> mean * x_vals-> mean ) / x_vals-> nsig2 );
+
+ return( x_vals );
+}
+
+#define LINREG_START_DEFN( TYPE ) static void *linreg_start_ ## TYPE( IMAGE *out, void *a, void *b ){ \
+ IMAGE **ins= (IMAGE **) a; \
+ x_set *x_vals= (x_set *) b; \
+ linreg_seq_ ## TYPE *seq= IM_NEW( out, linreg_seq_ ## TYPE ); \
+ \
+ if( ! seq ) \
+ return NULL; \
+ \
+ seq-> regs= im_start_many( NULL, ins, NULL ); \
+ seq-> ptrs= IM_ARRAY( out, x_vals-> n, TYPE* ); \
+ seq-> skips= IM_ARRAY( out, x_vals-> n, size_t ); \
+ \
+ if( ! seq-> ptrs || ! seq-> regs || ! seq-> skips ){ \
+ linreg_stop_ ## TYPE( seq, NULL, NULL ); \
+ return NULL; \
+ } \
+ return (void *) seq; \
+}
+
+#define N ( (double) n )
+#define y(a) ( (double) (* seq-> ptrs[(a)] ) )
+#define x(a) ( (double) ( x_vals-> xs[(a)] ) )
+#define xd(a) ( (double) ( x_vals-> difs[(a)] ) )
+#define Sxd2 ( x_vals-> nsig2 )
+#define mean_x ( x_vals-> mean )
+#define mean_y ( out[0] )
+#define dev_y ( out[1] )
+#define y_x0 ( out[2] )
+#define d_y_x0 ( out[3] )
+#define dy_dx ( out[4] )
+#define d_dy_dx ( out[5] )
+#define R ( out[6] )
+
+#define LINREG_GEN_DEFN( TYPE ) static int linreg_gen_ ## TYPE( REGION *to_make, void *vseq, void *unrequired, void *b ){ \
+ linreg_seq_ ## TYPE *seq= (linreg_seq_ ## TYPE *) vseq; \
+ x_set *x_vals= (x_set *) b; \
+ unsigned int n= x_vals-> n; \
+ double *out= (double*) IM_REGION_ADDR_TOPLEFT( to_make ); \
+ size_t out_skip= IM_REGION_LSKIP( to_make ) / sizeof( double ); \
+ double *out_end= out + out_skip * to_make-> valid. height; \
+ double *out_stop; \
+ size_t out_n= IM_REGION_N_ELEMENTS( to_make ); \
+ unsigned int i; \
+ \
+ out_skip-= out_n; \
+ \
+ if( im_prepare_many( seq-> regs, & to_make-> valid ) ) \
+ return -1; \
+ \
+ for( i= 0; i < n; ++i ){ \
+ seq-> ptrs[ i ]= (TYPE*) IM_REGION_ADDR( seq-> regs[ i ], to_make-> valid. left, to_make-> valid. top ); \
+ seq-> skips[ i ]= ( IM_REGION_LSKIP( seq-> regs[ i ] ) / sizeof( TYPE ) ) - IM_REGION_N_ELEMENTS( seq-> regs[ i ] ); \
+ } \
+ \
+ for( ; out < out_end; out+= out_skip, skip_all_ ## TYPE( seq-> ptrs, seq-> skips, n ) ) \
+ for( out_stop= out + out_n; out < out_stop; out+= 7, incr_all_ ## TYPE( seq-> ptrs, n ) ){ \
+ double Sy= 0.0; \
+ double Sxd_y= 0.0; \
+ double Syd2= 0.0; \
+ double Sxd_yd= 0.0; \
+ double Se2= 0.0; \
+ \
+ for( i= 0; i < n; ++i ){ \
+ Sy+= y(i); \
+ Sxd_y+= xd(i) * y(i); \
+ } \
+ mean_y= Sy / N; \
+ dy_dx= Sxd_y / Sxd2; \
+ y_x0= mean_y - dy_dx * mean_x; \
+ \
+ for( i= 0; i < n; ++i ){ \
+ double yd= y(i) - mean_y; \
+ double e= y(i) - dy_dx * x(i) - y_x0; \
+ Syd2+= yd * yd; \
+ Sxd_yd+= xd(i) * yd; \
+ Se2+= e * e; \
+ } \
+ dev_y= sqrt( Syd2 / N ); \
+ Se2/= ( N - 2.0 ); \
+ d_dy_dx= sqrt( Se2 / Sxd2 ); \
+ d_y_x0= sqrt( Se2 * x_vals-> err_term ); \
+ R= Sxd_yd / sqrt( Sxd2 * Syd2 ); \
+ } \
+ return 0; \
+}
+
+#define LINREG_STOP_DEFN( TYPE ) static int linreg_stop_ ## TYPE( void *vseq, void *a, void *b ){ \
+ linreg_seq_ ## TYPE *seq = (linreg_seq_ ## TYPE *) vseq; \
+ if( seq-> regs ) \
+ im_stop_many( seq-> regs, NULL, NULL ); \
+ return 0; \
+}
+
+#define INCR_ALL_DEFN( TYPE ) static void incr_all_ ## TYPE( TYPE **ptrs, unsigned int n ){ \
+ TYPE **stop= ptrs + n; \
+ for( ; ptrs < stop; ++ptrs ) \
+ ++*ptrs; \
+}
+
+#define SKIP_ALL_DEFN( TYPE ) static void skip_all_ ## TYPE( TYPE **ptrs, size_t *skips, unsigned int n ){ \
+ TYPE **stop= ptrs + n; \
+ for( ; ptrs < stop; ++ptrs, ++skips ) \
+ *ptrs+= *skips; \
+}
+
+LINREG_START_DEFN( gint8 );
+LINREG_START_DEFN( guint8 );
+LINREG_START_DEFN( gint16 );
+LINREG_START_DEFN( guint16 );
+LINREG_START_DEFN( gint32 );
+LINREG_START_DEFN( guint32 );
+LINREG_START_DEFN( float );
+LINREG_START_DEFN( double );
+
+LINREG_GEN_DEFN( gint8 );
+LINREG_GEN_DEFN( guint8 );
+LINREG_GEN_DEFN( gint16 );
+LINREG_GEN_DEFN( guint16 );
+LINREG_GEN_DEFN( gint32 );
+LINREG_GEN_DEFN( guint32 );
+LINREG_GEN_DEFN( float );
+LINREG_GEN_DEFN( double );
+
+LINREG_STOP_DEFN( gint8 );
+LINREG_STOP_DEFN( guint8 );
+LINREG_STOP_DEFN( gint16 );
+LINREG_STOP_DEFN( guint16 );
+LINREG_STOP_DEFN( gint32 );
+LINREG_STOP_DEFN( guint32 );
+LINREG_STOP_DEFN( float );
+LINREG_STOP_DEFN( double );
+
+INCR_ALL_DEFN( gint8 );
+INCR_ALL_DEFN( guint8 );
+INCR_ALL_DEFN( gint16 );
+INCR_ALL_DEFN( guint16 );
+INCR_ALL_DEFN( gint32 );
+INCR_ALL_DEFN( guint32 );
+INCR_ALL_DEFN( float );
+INCR_ALL_DEFN( double );
+
+SKIP_ALL_DEFN( gint8 );
+SKIP_ALL_DEFN( guint8 );
+SKIP_ALL_DEFN( gint16 );
+SKIP_ALL_DEFN( guint16 );
+SKIP_ALL_DEFN( gint32 );
+SKIP_ALL_DEFN( guint32 );
+SKIP_ALL_DEFN( float );
+SKIP_ALL_DEFN( double );
diff --git a/libvips/arithmetic/im_lintra.c b/libvips/arithmetic/im_lintra.c
new file mode 100644
index 00000000..af8af422
--- /dev/null
+++ b/libvips/arithmetic/im_lintra.c
@@ -0,0 +1,383 @@
+/* @(#) Pass an image through a linear transform - ie. out = in*a + b. Output
+ * @(#) is always float for integer input, double for double input, complex for
+ * @(#) complex input and double complex for double complex input.
+ * @(#)
+ * @(#) int
+ * @(#) im_lintra( a, in, b, out )
+ * @(#) IMAGE *in, *out;
+ * @(#) double a, b;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ * @(#)
+ *
+ * Copyright: 1990, N. Dessipris, based on im_powtra()
+ * Author: Nicos Dessipris
+ * Written on: 02/05/1990
+ * Modified on:
+ * 23/4/93 JC
+ * - adapted to work with partial images
+ * 1/7/93 JC
+ * - adapted for partial v2
+ * 7/10/94 JC
+ * - new IM_NEW()
+ * - more typedefs
+ * 9/2/95 JC
+ * - adapted for im_wrap...
+ * - operations on complex images now just transform the real channel
+ * 29/9/95 JC
+ * - complex was broken
+ * 15/4/97 JC
+ * - return(0) missing from generate, arrgh!
+ * 1/7/98 JC
+ * - im_lintra_vec added
+ * 3/8/02 JC
+ * - fall back to im_copy() for a == 1, b == 0
+ * 10/10/02 JC
+ * - auug, failing to multiply imag for complex! (thanks matt)
+ * 10/12/02 JC
+ * - removed im_copy() fallback ... meant that output format could change
+ * with value :-( very confusing
+ * 30/6/04
+ * - added 1 band image * n band vector case
+ * 8/12/06
+ * - add liboil support
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#ifdef HAVE_LIBOIL
+#include
+#endif /*HAVE_LIBOIL*/
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* Struct we need for im_generate().
+ */
+typedef struct {
+ int n; /* Number of bands of constants */
+ double *a, *b;
+} LintraInfo;
+
+/* Define what we do for each band element type. Non-complex input, any
+ * output.
+ */
+#define LOOP(IN, OUT) { \
+ IN *p = (IN *) in; \
+ OUT *q = (OUT *) out; \
+ \
+ for( x = 0; x < sz; x++ ) \
+ q[x] = a * (OUT) p[x] + b; \
+}
+
+/* Complex input, complex output.
+ */
+#define LOOPCMPLX(IN, OUT) {\
+ IN *p = (IN *) in; \
+ OUT *q = (OUT *) out; \
+ \
+ for( x = 0; x < sz; x++ ) { \
+ q[0] = a * p[0] + b; \
+ q[1] = a * p[1]; \
+ q += 2; \
+ p += 2; \
+ } \
+}
+
+#ifdef HAVE_LIBOIL
+/* Process granularity.
+ */
+#define CHUNKS (1000)
+
+/* d[] = s[] * b + c, with liboil
+ */
+static void
+lintra_f32( float *d, float *s, int n, float b, float c )
+{
+ float buf[CHUNKS];
+ int i;
+
+ for( i = 0; i < n; i += CHUNKS ) {
+ oil_scalarmultiply_f32_ns( buf, s,
+ &b, IM_MIN( CHUNKS, n - i ) );
+ oil_scalaradd_f32_ns( d, buf,
+ &c, IM_MIN( CHUNKS, n - i ) );
+
+ s += CHUNKS;
+ d += CHUNKS;
+ }
+}
+#endif /*HAVE_LIBOIL*/
+
+/* Lintra a buffer, 1 set of scale/offset.
+ */
+static int
+lintra1_gen( PEL *in, PEL *out, int width, IMAGE *im, LintraInfo *inf )
+{
+ double a = inf->a[0];
+ double b = inf->b[0];
+ int sz = width * im->Bands;
+ int x;
+
+ /* Lintra all input types.
+ */
+ switch( im->BandFmt ) {
+ case IM_BANDFMT_UCHAR: LOOP( unsigned char, float ); break;
+ case IM_BANDFMT_CHAR: LOOP( signed char, float ); break;
+ case IM_BANDFMT_USHORT: LOOP( unsigned short, float ); break;
+ case IM_BANDFMT_SHORT: LOOP( signed short, float ); break;
+ case IM_BANDFMT_UINT: LOOP( unsigned int, float ); break;
+ case IM_BANDFMT_INT: LOOP( signed int, float ); break;
+ case IM_BANDFMT_FLOAT:
+#ifdef HAVE_LIBOIL
+ lintra_f32( (float *) out, (float *) in, sz, a, b );
+#else /*!HAVE_LIBOIL*/
+ LOOP( float, float );
+#endif /*HAVE_LIBOIL*/
+ break;
+
+ case IM_BANDFMT_DOUBLE: LOOP( double, double ); break;
+ case IM_BANDFMT_COMPLEX: LOOPCMPLX( float, float ); break;
+ case IM_BANDFMT_DPCOMPLEX: LOOPCMPLX( double, double ); break;
+
+ default:
+ assert( 0 );
+ }
+
+ return( 0 );
+}
+
+/* Define what we do for each band element type. Non-complex input, any
+ * output.
+ */
+#define LOOPN(IN, OUT)\
+ {\
+ IN *p = (IN *) in;\
+ OUT *q = (OUT *) out;\
+ \
+ for( i = 0, x = 0; x < width; x++ )\
+ for( k = 0; k < nb; k++, i++ )\
+ q[i] = a[k] * (OUT) p[i] + b[k];\
+ }
+
+/* Complex input, complex output.
+ */
+#define LOOPCMPLXN(IN, OUT)\
+ {\
+ IN *p = (IN *) in;\
+ OUT *q = (OUT *) out;\
+ \
+ for( x = 0; x < width; x++ ) \
+ for( k = 0; k < nb; k++ ) {\
+ q[0] = a[k] * p[0] + b[k];\
+ q[1] = a[k] * p[1];\
+ q += 2;\
+ p += 2;\
+ }\
+ }
+
+/* Lintra a buffer, n set of scale/offset.
+ */
+static int
+lintran_gen( PEL *in, PEL *out, int width, IMAGE *im, LintraInfo *inf )
+{
+ double *a = inf->a;
+ double *b = inf->b;
+ int nb = im->Bands;
+ int i, x, k;
+
+ /* Lintra all input types.
+ */
+ switch( im->BandFmt ) {
+ case IM_BANDFMT_UCHAR: LOOPN( unsigned char, float ); break;
+ case IM_BANDFMT_CHAR: LOOPN( signed char, float ); break;
+ case IM_BANDFMT_USHORT: LOOPN( unsigned short, float ); break;
+ case IM_BANDFMT_SHORT: LOOPN( signed short, float ); break;
+ case IM_BANDFMT_UINT: LOOPN( unsigned int, float ); break;
+ case IM_BANDFMT_INT: LOOPN( signed int, float ); break;
+ case IM_BANDFMT_FLOAT: LOOPN( float, float ); break;
+ case IM_BANDFMT_DOUBLE: LOOPN( double, double ); break;
+ case IM_BANDFMT_COMPLEX: LOOPCMPLXN( float, float ); break;
+ case IM_BANDFMT_DPCOMPLEX: LOOPCMPLXN( double, double ); break;
+
+ default:
+ assert( 0 );
+ }
+
+ return( 0 );
+}
+
+/* 1 band image, n band vector.
+ */
+#define LOOPNV(IN, OUT) { \
+ IN *p = (IN *) in; \
+ OUT *q = (OUT *) out; \
+ \
+ for( i = 0, x = 0; x < width; x++ ) { \
+ OUT v = p[x]; \
+ \
+ for( k = 0; k < nb; k++, i++ ) \
+ q[i] = a[k] * v + b[k]; \
+ } \
+}
+
+#define LOOPCMPLXNV(IN, OUT) { \
+ IN *p = (IN *) in; \
+ OUT *q = (OUT *) out; \
+ \
+ for( x = 0; x < width; x++ ) { \
+ OUT p0 = p[0]; \
+ OUT p1 = p[1]; \
+ \
+ for( k = 0; k < nb; k++ ) { \
+ q[0] = a[k] * p0 + b[k]; \
+ q[1] = a[k] * p1; \
+ q += 2; \
+ } \
+ \
+ p += 2; \
+ } \
+}
+
+static int
+lintranv_gen( PEL *in, PEL *out, int width, IMAGE *im, LintraInfo *inf )
+{
+ double *a = inf->a;
+ double *b = inf->b;
+ int nb = inf->n;
+ int i, x, k;
+
+ /* Lintra all input types.
+ */
+ switch( im->BandFmt ) {
+ case IM_BANDFMT_UCHAR: LOOPNV( unsigned char, float ); break;
+ case IM_BANDFMT_CHAR: LOOPNV( signed char, float ); break;
+ case IM_BANDFMT_USHORT: LOOPNV( unsigned short, float ); break;
+ case IM_BANDFMT_SHORT: LOOPNV( signed short, float ); break;
+ case IM_BANDFMT_UINT: LOOPNV( unsigned int, float ); break;
+ case IM_BANDFMT_INT: LOOPNV( signed int, float ); break;
+ case IM_BANDFMT_FLOAT: LOOPNV( float, float ); break;
+ case IM_BANDFMT_DOUBLE: LOOPNV( double, double ); break;
+ case IM_BANDFMT_COMPLEX: LOOPCMPLXNV( float, float ); break;
+ case IM_BANDFMT_DPCOMPLEX: LOOPCMPLXNV( double, double ); break;
+
+ default:
+ assert( 0 );
+ }
+
+ return( 0 );
+}
+
+/* Linear transform n bands.
+ */
+int
+im_lintra_vec( int n, double *a, IMAGE *in, double *b, IMAGE *out )
+{
+ LintraInfo *inf;
+ int i;
+
+ /* Check args.
+ */
+ if( in->Coding != IM_CODING_NONE ) {
+ im_error( "im_lintra_vec", "%s", _( "not uncoded" ) );
+ return( -1 );
+ }
+
+ /* If n and bands differ, one of them must be one (and we multiplex
+ * the other).
+ */
+ if( n != in->Bands && (n != 1 && in->Bands != 1) ) {
+ im_error( "im_lintra_vec",
+ _( "not 1 or %d elements in vector" ), in->Bands );
+ return( -1 );
+ }
+
+ /* Prepare output header.
+ */
+ if( im_cp_desc( out, in ) )
+ return( -1 );
+ if( im_isint( in ) ) {
+ out->Bbits = IM_BBITS_FLOAT;
+ out->BandFmt = IM_BANDFMT_FLOAT;
+ }
+ if( in->Bands == 1 )
+ out->Bands = n;
+
+ /* Make space for a little buffer.
+ */
+ if( !(inf = IM_NEW( out, LintraInfo )) ||
+ !(inf->a = IM_ARRAY( out, n, double )) ||
+ !(inf->b = IM_ARRAY( out, n, double )) )
+ return( -1 );
+ inf->n = n;
+ for( i = 0; i < n; i++ ) {
+ inf->a[i] = a[i];
+ inf->b[i] = b[i];
+ }
+
+ /* Generate!
+ */
+ if( n == 1 ) {
+ if( im_wrapone( in, out,
+ (im_wrapone_fn) lintra1_gen, in, inf ) )
+ return( -1 );
+ }
+ else if( in->Bands == 1 ) {
+ if( im_wrapone( in, out,
+ (im_wrapone_fn) lintranv_gen, in, inf ) )
+ return( -1 );
+ }
+ else {
+ if( im_wrapone( in, out,
+ (im_wrapone_fn) lintran_gen, in, inf ) )
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+/* Linear transform.
+ */
+int
+im_lintra( double a, IMAGE *in, double b, IMAGE *out )
+{
+ return( im_lintra_vec( 1, &a, in, &b, out ) );
+}
diff --git a/libvips/arithmetic/im_litecor.c b/libvips/arithmetic/im_litecor.c
new file mode 100644
index 00000000..9b4aa577
--- /dev/null
+++ b/libvips/arithmetic/im_litecor.c
@@ -0,0 +1,321 @@
+/* @(#) Function to perform lighting correction.
+ * @(#) One band IM_BANDFMT_UCHAR images only. Always writes UCHAR.
+ * @(#)
+ * @(#) Function im_litecor() assumes that imin
+ * @(#) is either memory mapped or in a buffer.
+ * @(#)
+ * @(#) int im_litecor(in, w, out, clip, factor)
+ * @(#) IMAGE *in, *w, *out;
+ * @(#) int clip;
+ * @(#) double factor;
+ * @(#)
+ * @(#) clip==1
+ * @(#) - Compute max(white)*factor*(image/white), Clip to 255.
+ * @(#) clip==0
+ * @(#) - Compute factor for you.
+ * @(#)
+ * @(#)
+ * @(#)
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ *
+ * Copyright: 1990, J. Cupitt, 1991 N. Dessipris
+ *
+ * Author: J. Cupitt, N. Dessipris
+ * Written on: 02/08/1990
+ * Modified on : 6/11/1991, by ND to produce a UCHAR output
+ * 1/4/93 J.Cupitt
+ * - bugs if white is smaller than image fixed
+ * - im_warning() now called
+ * - clip==0 case not tested or changed! do not use!
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* If maximum output is > 255 scale output between minout and maxout,
+ * by normalising maxout to 255.
+ * If maximum output is < 255 do the light correction without scaling
+ */
+static int
+im_litecor0( in, white, out )
+IMAGE *in, *white, *out;
+{ PEL *p, *w;
+ PEL *q, *bu;
+ int c;
+ int x, y;
+ float xrat = (float) in->Xsize / white->Xsize;
+ float yrat = (float) in->Ysize / white->Ysize;
+ int xstep = (int) xrat;
+ int ystep = (int) yrat;
+ double max;
+ int wtmp, maxw, maxout, temp;
+
+ /* Check white is some simple multiple of image.
+ */
+ if( xrat < 1.0 || xrat != xstep || yrat < 1.0 || yrat != ystep ) {
+ im_error( "im_litecor", "white not simple scale of image" );
+ return( -1 );
+ }
+
+ /* Find the maximum of the white.
+ */
+ if( im_max( white, &max ) )
+ return( -1 );
+ maxw = (int)max;
+
+ /* Set up the output header.
+ */
+ if( im_cp_desc( out, in ) )
+ return( -1 );
+ if( im_setupout( out ) )
+ return( -1 );
+
+ /* Make buffer for outputting to.
+ */
+ if( !(bu = (PEL *) im_malloc( out, out->Xsize )) )
+ return( -1 );
+
+ /* Find largest value we might generate if factor == 1.0
+ */
+ maxout = -1;
+ p = (PEL *) in->data;
+ for( y = 0; y < in->Ysize; y++ ) {
+ /* Point w to the start of the line in the white
+ * corresponding to the line we are about to correct. c counts
+ * up to xstep; each time it wraps, we should move w on one.
+ */
+ w = (PEL *) (white->data + white->Xsize * (int)(y/ystep));
+ c = 0;
+
+ /* Scan along line.
+ */
+ for( x = 0; x < out->Xsize; x++ ) {
+ wtmp = (int)*w;
+ temp = ( maxw * (int) *p++ + (wtmp>>1) ) / wtmp;
+ if (temp > maxout )
+ maxout = temp;
+
+ /* Move white pointer on if necessary. */
+ c++;
+ if( c == xstep ) {
+ w++;
+ c = 0;
+ }
+ }
+ }
+
+ /* Do exactly the same as above by scaling the result with respect to
+ * maxout
+ */
+ p = (PEL *) in->data;
+ if (maxout <= 255 ) /* no need for rescaling output */
+ {
+ for( y = 0; y < in->Ysize; y++ )
+ {
+ q = bu;
+ w = (PEL *) (white->data +
+ white->Xsize * (int)(y/ystep));
+ c = 0;
+
+ /* Scan along line. */
+ for( x = 0; x < in->Xsize; x++ )
+ {
+ wtmp = (int)*w;
+ *q++ = (PEL)
+ ( ( maxw * (int) *p++ + (wtmp>>1) ) / wtmp );
+ /* Move white pointer on if necessary.
+ */
+ c++;
+ if( c == xstep ) { w++; c = 0; }
+ }
+ if( im_writeline( y, out, bu ) )
+ {
+ im_error("im_litecor", "im_writeline failed");
+ return( -1 );
+ }
+ }
+ }
+ else /* rescale output wrt maxout */
+ {
+ for( y = 0; y < in->Ysize; y++ )
+ {
+ q = bu;
+ w = (PEL *) (white->data +
+ white->Xsize * (int)(y/ystep));
+ c = 0;
+
+ /* Scan along line. */
+ for( x = 0; x < in->Xsize; x++ )
+ {
+ wtmp = maxout * ((int)*w);
+ *q++ = (PEL)
+ ( ( maxw * (int) *p++ * 255 + (wtmp>>1)) / wtmp );
+ /* Move white pointer on if necessary.
+ */
+ c++;
+ if( c == xstep ) { w++; c = 0; }
+ }
+ if( im_writeline( y, out, bu ) )
+ {
+ im_error("im_litecor", "im_writeline failed");
+ return( -1 );
+ }
+ }
+ }
+
+ return( 0 );
+}
+
+/* Clip all corrected values above 255, if any.
+ */
+static int
+im_litecor1( in, white, out, factor )
+IMAGE *in, *white, *out;
+double factor;
+{ PEL *p, *w;
+ PEL *q, *bu;
+ int c;
+ int x, y;
+ float xrat = (float) in->Xsize / white->Xsize;
+ float yrat = (float) in->Ysize / white->Ysize;
+ int xstep = (int) xrat;
+ int ystep = (int) yrat;
+ double max;
+ double maxw, temp;
+ int nclipped = 0;
+
+ /* Check white is some simple multiple of image.
+ */
+ if( xrat < 1.0 || xrat != xstep || yrat < 1.0 || yrat != ystep ) {
+ im_error( "im_litecor", "white not simple scale of image" );
+ return( -1 );
+ }
+
+ /* Find the maximum of the white.
+ */
+ if( im_max( white, &max ) )
+ return( -1 );
+ maxw = max;
+
+ /* Set up the output header.
+ */
+ if( im_cp_desc( out, in ) )
+ return( -1 );
+ if( im_setupout( out ) )
+ return( -1 );
+
+ /* Make buffer we write to.
+ */
+ if( !(bu = (PEL *) im_malloc( out, out->Xsize )) )
+ return( -1 );
+
+ /* Loop through sorting max output
+ */
+ p = (PEL *) in->data;
+ for( y = 0; y < in->Ysize; y++ ) {
+ q = bu;
+ w = (PEL *) (white->data + white->Xsize * (int)(y / ystep));
+ c = 0;
+
+ for( x = 0; x < out->Xsize; x++ ) {
+ temp = ((factor * maxw * (int) *p++)/((int) *w)) + 0.5;
+ if( temp > 255.0 ) {
+ temp = 255;
+ nclipped++;
+ }
+ *q++ = temp;
+
+ /* Move white pointer on if necessary.
+ */
+ c++;
+ if( c == xstep ) {
+ w++;
+ c = 0;
+ }
+ }
+
+ if( im_writeline( y, out, bu ) )
+ return( -1 );
+ }
+
+ if( nclipped )
+ im_warn( "im_litecor", "%d pels over 255 clipped", nclipped );
+
+ return( 0 );
+}
+
+/* Lighting correction. One band uchar images only.
+ * Assumes the white is some simple multiple of the image in size; ie. the
+ * white has been taken with some smaller or equal set of resolution
+ * parameters.
+ */
+int
+im_litecor( in, white, out, clip, factor )
+IMAGE *in, *white, *out;
+int clip;
+double factor;
+{ /* Check our args.
+ */
+ if( im_iocheck( in, out ) )
+ return( -1 );
+ if( in->Bands != 1 || in->Bbits != 8 ||
+ in->Coding != IM_CODING_NONE || in->BandFmt != IM_BANDFMT_UCHAR ) {
+ im_error( "im_litecor", "bad input format" );
+ return( -1 );
+ }
+ if( white->Bands != 1 || white->Bbits != 8 ||
+ white->Coding != IM_CODING_NONE || white->BandFmt != IM_BANDFMT_UCHAR ) {
+ im_error( "im_litecor", "bad white format" );
+ return( -1 );
+ }
+
+ switch( clip ) {
+ case 1:
+ return( im_litecor1( in, white, out, factor ) );
+
+ case 0:
+ return( im_litecor0( in, white, out ) );
+
+ default:
+ im_error( "im_litecor", "unknown flag %d", clip );
+ return( -1 );
+ }
+}
diff --git a/libvips/arithmetic/im_log10tra.c b/libvips/arithmetic/im_log10tra.c
new file mode 100644
index 00000000..45399112
--- /dev/null
+++ b/libvips/arithmetic/im_log10tra.c
@@ -0,0 +1,167 @@
+/* @(#) Find base 10 log of any non-complex image. Output
+ * @(#) is always float for integer input and double for double input.
+ * @(#)
+ * @(#) int
+ * @(#) im_log10tra( in, out )
+ * @(#) IMAGE *in, *out;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ * @(#)
+ *
+ * Copyright: 1990, N. Dessipris, based on im_powtra()
+ * Author: Nicos Dessipris
+ * Written on: 02/05/1990
+ * Modified on:
+ * 5/5/93 JC
+ * - adapted from im_lintra to work with partial images
+ * - incorrect implementation of complex logs removed
+ * 1/7/93 JC
+ * - adapted for partial v2
+ * - ANSIfied
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* Define what we do for each band element type. Non-complex input, any
+ * output.
+ */
+#define loop(IN, OUT)\
+ for( y = to; y < bo; y++ ) {\
+ IN *p = (IN *) IM_REGION_ADDR( ir, le, y );\
+ OUT *q = (OUT *) IM_REGION_ADDR( or, le, y );\
+ \
+ for( x = 0; x < sz; x++ )\
+ *q++ = log10( *p++ );\
+ }
+
+/* log10tra a small area.
+ */
+static int
+log10tra_gen( REGION *or, void *seq, void *a, void *b )
+{
+ REGION *ir = (REGION *) seq;
+ Rect *r = &or->valid;
+ int le = r->left;
+ int to = r->top;
+ int bo = IM_RECT_BOTTOM(r);
+ int sz = IM_REGION_N_ELEMENTS( or );
+ int x, y;
+
+ /* Ask for input we need.
+ */
+ if( im_prepare( ir, r ) )
+ return( -1 );
+
+ /* log10tra all input types.
+ */
+ switch( ir->im->BandFmt ) {
+ case IM_BANDFMT_UCHAR: loop(unsigned char, float); break;
+ case IM_BANDFMT_CHAR: loop(signed char, float); break;
+ case IM_BANDFMT_USHORT: loop(unsigned short, float); break;
+ case IM_BANDFMT_SHORT: loop(signed short, float); break;
+ case IM_BANDFMT_UINT: loop(unsigned int, float); break;
+ case IM_BANDFMT_INT: loop(signed int, float); break;
+ case IM_BANDFMT_FLOAT: loop(float, float); break;
+ case IM_BANDFMT_DOUBLE: loop(double, double); break;
+
+ default:
+ assert( 0 );
+ }
+
+ return( 0 );
+}
+
+/* Log 10 transform.
+ */
+int
+im_log10tra( IMAGE *in, IMAGE *out )
+{
+ /* Check args.
+ */
+ if( im_piocheck( in, out ) )
+ return( -1 );
+ if( in->Coding != IM_CODING_NONE ) {
+ im_error( "im_log10tra", "%s", _( "not uncoded" ) );
+ return( -1 );
+ }
+ if( im_iscomplex( in ) ) {
+ im_error( "im_log10tra", "%s", _( "not non-complex" ) );
+ return( -1 );
+ }
+
+ /* Prepare output header.
+ */
+ if( im_cp_desc( out, in ) )
+ return( -1 );
+ switch( in->BandFmt ) {
+ case IM_BANDFMT_UCHAR:
+ case IM_BANDFMT_CHAR:
+ case IM_BANDFMT_USHORT:
+ case IM_BANDFMT_SHORT:
+ case IM_BANDFMT_UINT:
+ case IM_BANDFMT_INT:
+ out->Bbits = IM_BBITS_FLOAT;
+ out->BandFmt = IM_BANDFMT_FLOAT;
+ break;
+
+ case IM_BANDFMT_FLOAT:
+ case IM_BANDFMT_DOUBLE:
+ break;
+
+ default:
+ assert( 0 );
+ }
+
+ /* Set demand hints.
+ */
+ if( im_demand_hint( out, IM_THINSTRIP, in, NULL ) )
+ return( -1 );
+
+ /* Generate!
+ */
+ if( im_generate( out,
+ im_start_one, log10tra_gen, im_stop_one, in, NULL ) )
+ return( -1 );
+
+ return( 0 );
+}
diff --git a/libvips/arithmetic/im_logtra.c b/libvips/arithmetic/im_logtra.c
new file mode 100644
index 00000000..d29861af
--- /dev/null
+++ b/libvips/arithmetic/im_logtra.c
@@ -0,0 +1,167 @@
+/* @(#) Find natural log of any non-complex image. Output
+ * @(#) is always float for integer input and double for double input.
+ * @(#)
+ * @(#) int
+ * @(#) im_logtra( in, out )
+ * @(#) IMAGE *in, *out;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ * @(#)
+ *
+ * Copyright: 1990, N. Dessipris, based on im_powtra()
+ * Author: Nicos Dessipris
+ * Written on: 02/05/1990
+ * Modified on:
+ * 5/5/93 JC
+ * - adapted from im_lintra to work with partial images
+ * - incorrect implementation of complex logs removed
+ * 1/7/93 JC
+ * - adapted for partial v2
+ * - ANSIfied
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* Define what we do for each band element type. Non-complex input, any
+ * output.
+ */
+#define loop(IN, OUT)\
+ for( y = to; y < bo; y++ ) {\
+ IN *p = (IN *) IM_REGION_ADDR( ir, le, y );\
+ OUT *q = (OUT *) IM_REGION_ADDR( or, le, y );\
+ \
+ for( x = 0; x < sz; x++ )\
+ *q++ = log( *p++ );\
+ }
+
+/* logtra a small area.
+ */
+static int
+logtra_gen( REGION *or, void *seq, void *a, void *b )
+{
+ REGION *ir = (REGION *) seq;
+ Rect *r = &or->valid;
+ int le = r->left;
+ int to = r->top;
+ int bo = IM_RECT_BOTTOM(r);
+ int sz = IM_REGION_N_ELEMENTS( or );
+ int x, y;
+
+ /* Ask for input we need.
+ */
+ if( im_prepare( ir, r ) )
+ return( -1 );
+
+ /* logtra all input types.
+ */
+ switch( ir->im->BandFmt ) {
+ case IM_BANDFMT_UCHAR: loop(unsigned char, float); break;
+ case IM_BANDFMT_CHAR: loop(signed char, float); break;
+ case IM_BANDFMT_USHORT: loop(unsigned short, float); break;
+ case IM_BANDFMT_SHORT: loop(signed short, float); break;
+ case IM_BANDFMT_UINT: loop(unsigned int, float); break;
+ case IM_BANDFMT_INT: loop(signed int, float); break;
+ case IM_BANDFMT_FLOAT: loop(float, float); break;
+ case IM_BANDFMT_DOUBLE: loop(double, double); break;
+
+ default:
+ assert( 0 );
+ }
+
+ return( 0 );
+}
+
+/* Log transform.
+ */
+int
+im_logtra( IMAGE *in, IMAGE *out )
+{
+ /* Check args.
+ */
+ if( im_piocheck( in, out ) )
+ return( -1 );
+ if( in->Coding != IM_CODING_NONE ) {
+ im_error( "im_logtra", "%s", _( "not uncoded" ) );
+ return( -1 );
+ }
+ if( im_iscomplex( in ) ) {
+ im_error( "im_logtra", "%s", _( "not non-complex" ) );
+ return( -1 );
+ }
+
+ /* Prepare output header.
+ */
+ if( im_cp_desc( out, in ) )
+ return( -1 );
+ switch( in->BandFmt ) {
+ case IM_BANDFMT_UCHAR:
+ case IM_BANDFMT_CHAR:
+ case IM_BANDFMT_USHORT:
+ case IM_BANDFMT_SHORT:
+ case IM_BANDFMT_UINT:
+ case IM_BANDFMT_INT:
+ out->Bbits = IM_BBITS_FLOAT;
+ out->BandFmt = IM_BANDFMT_FLOAT;
+ break;
+
+ case IM_BANDFMT_FLOAT:
+ case IM_BANDFMT_DOUBLE:
+ break;
+
+ default:
+ assert( 0 );
+ }
+
+ /* Set demand hints.
+ */
+ if( im_demand_hint( out, IM_THINSTRIP, in, NULL ) )
+ return( -1 );
+
+ /* Generate!
+ */
+ if( im_generate( out,
+ im_start_one, logtra_gen, im_stop_one, in, NULL ) )
+ return( -1 );
+
+ return( 0 );
+}
diff --git a/libvips/arithmetic/im_max.c b/libvips/arithmetic/im_max.c
new file mode 100644
index 00000000..172a533b
--- /dev/null
+++ b/libvips/arithmetic/im_max.c
@@ -0,0 +1,249 @@
+/* @(#) Function to find the maximim of an image. Works for any
+ * @(#) image type. Returns a double.
+ * @(#)
+ * @(#) int im_max(in, max)
+ * @(#) IMAGE *in;
+ * @(#) double *max;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ *
+ * Copyright: 1990, J. Cupitt
+ *
+ * Author: J. Cupitt
+ * Written on: 02/05/1990
+ * Modified on : 18/03/1991, N. Dessipris
+ * 7/7/93 JC
+ * - complex case fixed
+ * - im_incheck() call added
+ * 20/6/95 JC
+ * - now returns double
+ * - modernised a little
+ * - now returns max square amplitude rather than amplitude for complex
+ * 9/5/02 JC
+ * - partialed
+ * 3/4/02 JC
+ * - random wrong result for >1 thread :-( (thanks Joe)
+ * 15/10/07
+ * - oh, heh, seq->inf was not being set correctly, not that it mattered
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+/*
+#define DEBUG
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* Per-call state.
+ */
+typedef struct _MaxInfo {
+ /* Parameters.
+ */
+ IMAGE *in;
+ double *out;
+
+ /* Global max so far.
+ */
+ double value;
+ int valid; /* zero means value is unset */
+} MaxInfo;
+
+/* Per thread state.
+ */
+typedef struct _Seq {
+ MaxInfo *inf;
+
+ double value;
+ int valid; /* zero means value is unset */
+} Seq;
+
+/* New sequence value.
+ */
+static void *
+max_start( IMAGE *in, void *a, void *b )
+{
+ MaxInfo *inf = (MaxInfo *) a;
+ Seq *seq = IM_NEW( NULL, Seq );
+
+ seq->inf = inf;
+ seq->valid = 0;
+
+ return( (void *) seq );
+}
+
+/* Merge the sequence value back into the per-call state.
+ */
+static int
+max_stop( void *vseq, void *a, void *b )
+{
+ Seq *seq = (Seq *) vseq;
+ MaxInfo *inf = (MaxInfo *) a;
+
+ if( seq->valid ) {
+ if( !inf->valid )
+ /* Just copy.
+ */
+ inf->value = seq->value;
+ else
+ /* Merge.
+ */
+ inf->value = IM_MAX( inf->value, seq->value );
+
+ inf->valid = 1;
+ }
+
+ im_free( seq );
+
+ return( 0 );
+}
+
+/* Loop over region, adding to seq.
+ */
+static int
+max_scan( REGION *reg, void *vseq, void *a, void *b )
+{
+ Seq *seq = (Seq *) vseq;
+ Rect *r = ®->valid;
+ IMAGE *im = reg->im;
+ int le = r->left;
+ int to = r->top;
+ int bo = IM_RECT_BOTTOM(r);
+ int nel = IM_REGION_N_ELEMENTS( reg );
+
+ int x, y;
+
+ double m;
+
+#define loop(TYPE) { \
+ m = *((TYPE *) IM_REGION_ADDR( reg, le, to )); \
+ \
+ for( y = to; y < bo; y++ ) { \
+ TYPE *p = (TYPE *) IM_REGION_ADDR( reg, le, y ); \
+ \
+ for( x = 0; x < nel; x++ ) { \
+ double v = p[x]; \
+ \
+ if( v > m ) \
+ m = v; \
+ } \
+ } \
+}
+
+#define complex_loop(TYPE) { \
+ TYPE *p = (TYPE *) IM_REGION_ADDR( reg, le, to ); \
+ double real = p[0]; \
+ double imag = p[1]; \
+ \
+ m = real * real + imag * imag; \
+ \
+ for( y = to; y < bo; y++ ) { \
+ TYPE *p = (TYPE *) IM_REGION_ADDR( reg, le, y ); \
+ \
+ for( x = 0; x < nel * 2; x += 2 ) { \
+ double mod; \
+ \
+ real = p[x]; \
+ imag = p[x + 1]; \
+ mod = real * real + imag * imag; \
+ \
+ if( mod > m ) \
+ m = mod; \
+ } \
+ } \
+}
+
+ switch( im->BandFmt ) {
+ case IM_BANDFMT_UCHAR: loop( unsigned char ); break;
+ case IM_BANDFMT_CHAR: loop( signed char ); break;
+ case IM_BANDFMT_USHORT: loop( unsigned short ); break;
+ case IM_BANDFMT_SHORT: loop( signed short ); break;
+ case IM_BANDFMT_UINT: loop( unsigned int ); break;
+ case IM_BANDFMT_INT: loop( signed int ); break;
+ case IM_BANDFMT_FLOAT: loop( float ); break;
+ case IM_BANDFMT_DOUBLE: loop( double ); break;
+ case IM_BANDFMT_COMPLEX: complex_loop( float ); break;
+ case IM_BANDFMT_DPCOMPLEX: complex_loop( double ); break;
+
+ default:
+ assert( 0 );
+ }
+
+ if( seq->valid ) {
+ seq->value = IM_MAX( seq->value, m );
+ }
+ else {
+ seq->value = m;
+ seq->valid = 1;
+ }
+
+#ifdef DEBUG
+ printf( "im_max: left = %d, top = %d, width = %d, height = %d\n",
+ r->left, r->top, r->width, r->height );
+ printf( " (max = %g)\n", seq->value );
+#endif /*DEBUG*/
+
+ return( 0 );
+}
+
+int
+im_max( IMAGE *in, double *out )
+{
+ MaxInfo inf;
+
+ inf.in = in;
+ inf.out = out;
+ inf.valid = 0;
+
+ if( im_pincheck( in ) )
+ return( -1 );
+ if( in->Coding != IM_CODING_NONE ) {
+ im_error( "im_max", "%s", _( "not uncoded" ) );
+ return( -1 );
+ }
+
+ if( im_iterate( in, max_start, max_scan, max_stop, &inf, NULL ) )
+ return( -1 );
+
+ *out = inf.value;
+
+ return( 0 );
+}
diff --git a/libvips/arithmetic/im_maxpos.c b/libvips/arithmetic/im_maxpos.c
new file mode 100644
index 00000000..3a25214f
--- /dev/null
+++ b/libvips/arithmetic/im_maxpos.c
@@ -0,0 +1,151 @@
+/* @(#) Function to find the maximum of an image. Works for any
+ * @(#) image type. Returns a double and the location of max.
+ * @(#)
+ * @(#) Function im_maxpos() assumes that input
+ * @(#) is either memory mapped or in a buffer.
+ * @(#)
+ * @(#) int im_maxpos(in, xpos, ypos, max)
+ * @(#) IMAGE *in;
+ * @(#) int *xpos, *ypos;
+ * @(#) double *max;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ *
+ * Copyright: 1990, J. Cupitt
+ *
+ * Author: J. Cupitt
+ * Written on: 02/05/1990
+ * Modified on : 18/03/1991, N. Dessipris
+ * 23/11/92: J.Cupitt - correct result for more than 1 band now.
+ * 23/7/93 JC
+ * - im_incheck() call added
+ * 20/6/95 JC
+ * - now returns double for value, like im_max()
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* Useful: Call a macro with the name, type pairs for all VIPS functions.
+ */
+#define im_for_all_types() \
+ case IM_BANDFMT_UCHAR: loop(unsigned char); break; \
+ case IM_BANDFMT_CHAR: loop(signed char); break; \
+ case IM_BANDFMT_USHORT: loop(unsigned short); break; \
+ case IM_BANDFMT_SHORT: loop(signed short); break; \
+ case IM_BANDFMT_UINT: loop(unsigned int); break; \
+ case IM_BANDFMT_INT: loop(signed int); break; \
+ case IM_BANDFMT_FLOAT: loop(float); break; \
+ case IM_BANDFMT_DOUBLE: loop(double); break; \
+ case IM_BANDFMT_COMPLEX: loopcmplx(float); break; \
+ case IM_BANDFMT_DPCOMPLEX: loopcmplx(double); break;
+
+/* Find the position of the maximum of an image. Take any format, returns a
+ * float and its position.
+ */
+int
+im_maxpos( IMAGE *in, int *xpos, int *ypos, double *out )
+{
+ double m;
+ int xp=0, yp=0;
+ int os;
+
+/* Check our args. */
+ if( im_incheck( in ) )
+ return( -1 );
+ if( in->Coding != IM_CODING_NONE ) {
+ im_error( "im_maxpos", "%s", _( "not uncoded" ) );
+ return( -1 );
+ }
+
+/* What type? First define the loop we want to perform for all types. */
+#define loop(TYPE) \
+ { TYPE *p = (TYPE *) in->data; \
+ int x, y; \
+ m = (double) *p; \
+ \
+ for ( y=0; yYsize; y++ ) \
+ for ( x=0; x m ) {\
+ m = (double) *p; \
+ xp = x; yp = y; \
+ }\
+ p++ ;\
+ }\
+ }
+
+#define loopcmplx(TYPE) \
+ { TYPE *p = (TYPE *) in->data; \
+ double re=(double)*p;\
+ double im=(double)*(p+1);\
+ double mod = re * re + im * im;\
+ int x, y; \
+ m = mod; \
+ \
+ for ( y=0; yYsize; y++ ) \
+ for ( x=0; x m ) {\
+ m = mod; \
+ xp = x; yp = y; \
+ }\
+ }\
+ }
+
+/* Now generate code for all types. */
+ os = in->Xsize * in->Bands;
+ switch( in->BandFmt ) {
+ im_for_all_types();
+ default: {
+ assert( 0 );
+ return( -1 );
+ }
+ }
+
+ /* Return maxima and position of maxima. Nasty: we divide the xpos by
+ * the number of bands to get the position in pixels.
+ */
+ *out = m;
+ *xpos = xp / in->Bands;
+ *ypos = yp;
+
+ return( 0 );
+}
diff --git a/libvips/arithmetic/im_maxpos_avg.c b/libvips/arithmetic/im_maxpos_avg.c
new file mode 100644
index 00000000..5427aaa1
--- /dev/null
+++ b/libvips/arithmetic/im_maxpos_avg.c
@@ -0,0 +1,201 @@
+/* @(#) Function to find the maximum of an image. Returns coords and value at
+ * @(#) double precision. In the event of a draw, returns average of all
+ * @(#) drawing coords, and interpolated value at that position.
+ * @(#)
+ * @(#) int im_maxpos_avg(
+ * @(#) IMAGE *im,
+ * @(#) double *xpos,
+ * @(#) double *ypos,
+ * @(#) double *out
+ * @(#) );
+ * @(#)
+ *
+ * Copyright: 2006, The Nottingham Trent University
+ * Copyright: 2006, Tom Vajzovic
+ *
+ * Author: Tom Vajzovic
+ *
+ * Written on: 2006-09-25
+ * 15/10/07 JC
+ * - changed spelling of occurrences
+ * - check for !occurrences before using val
+ * - renamed avg as sum, a bit clearer
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+
+/** HEADERS **/
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /* HAVE_CONFIG_H */
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC */
+
+
+/** LOCAL TYPES **/
+
+typedef struct {
+ double x_sum;
+ double y_sum;
+ double val;
+ unsigned int occurrences;
+
+} pos_avg_t;
+
+
+/** LOCAL FUNCTIONS DECLARATIONS **/
+
+static void *maxpos_avg_start( IMAGE *im , void *, void * );
+static int maxpos_avg_scan( REGION *reg, void *seq, void *, void * );
+static int maxpos_avg_stop( void *seq, void *, void * );
+
+
+/** EXPORTED FUNCTION **/
+
+int im_maxpos_avg( IMAGE *im, double *xpos, double *ypos, double *out ){
+#define FUNCTION_NAME "im_maxpos_avg"
+
+ pos_avg_t master= { 0.0, 0.0, 0.0, 0 };
+
+ if( im_pincheck( im ) )
+ return -1;
+
+ if( im-> Coding ){
+ im_error( FUNCTION_NAME, "%s", _("uncoded images only") );
+ return -1;
+ }
+ if( !( im_isint( im ) || im_isfloat( im ) ) ){
+ im_error( FUNCTION_NAME, "%s", _("scalar images only") );
+ return -1;
+ }
+ if( 1 != im-> Bands ){
+ im_error( FUNCTION_NAME, "%s", _("single band images only") );
+ return -1;
+ }
+ if( ! xpos || ! ypos || ! out ){
+ im_error( FUNCTION_NAME, "%s", _("invalid argument") );
+ return -1;
+ }
+ if( im_iterate( im, maxpos_avg_start, maxpos_avg_scan, maxpos_avg_stop, &master, NULL ) )
+ return -1;
+
+ *xpos= master. x_sum / master. occurrences;
+ *ypos= master. y_sum / master. occurrences;
+
+ return im_point_bilinear( im, *xpos, *ypos, 0, out );
+
+#undef FUNCTION_NAME
+}
+
+static void *maxpos_avg_start( IMAGE *im, void *a, void *b ){
+ pos_avg_t *seq;
+
+ seq= IM_NEW( NULL, pos_avg_t );
+ if( ! seq )
+ return NULL;
+
+ seq-> x_sum= 0.0;
+ seq-> y_sum= 0.0;
+ seq-> val= 0.0;
+ seq-> occurrences= 0;
+
+ return (void *) seq;
+}
+
+/* should be void (always returns 0) */
+static int maxpos_avg_scan( REGION *reg, void *vseq, void *a, void *b ) {
+
+ pos_avg_t *seq= (pos_avg_t *) vseq;
+ const int right= reg-> valid. left + reg-> valid. width;
+ const int bottom= reg-> valid. top + reg-> valid. height;
+ int x;
+ int y;
+
+#define LOOPS(type){ \
+ type *read= (type*) IM_REGION_ADDR( reg, reg-> valid. left, reg-> valid. top ) - reg-> valid. left; \
+ size_t skip= IM_REGION_LSKIP( reg ) / sizeof( type ); \
+ \
+ for( y= reg-> valid. top; y < bottom; ++y, read+= skip ) \
+ for( x= reg-> valid. left; x < right; ++x ) \
+ if( !seq-> occurrences || \
+ read[x] > seq-> val ){ \
+ seq-> val= read[x]; \
+ seq-> x_sum= x; \
+ seq-> y_sum= y; \
+ seq-> occurrences= 1; \
+ } \
+ else if( read[x] == seq-> val ){ \
+ seq-> x_sum+= x; \
+ seq-> y_sum+= y; \
+ ++ (seq-> occurrences); \
+ } \
+}
+
+ switch( reg-> im-> BandFmt ){
+ case IM_BANDFMT_CHAR: LOOPS( gint8 ) break;
+ case IM_BANDFMT_UCHAR: LOOPS( guint8 ) break;
+ case IM_BANDFMT_SHORT: LOOPS( gint16 ) break;
+ case IM_BANDFMT_USHORT: LOOPS( guint16 ) break;
+ case IM_BANDFMT_INT: LOOPS( gint32 ) break;
+ case IM_BANDFMT_UINT: LOOPS( guint32 ) break;
+ case IM_BANDFMT_FLOAT: LOOPS( float ) break;
+ case IM_BANDFMT_DOUBLE: LOOPS( double ) break;
+ }
+
+ return 0;
+#undef LOOPS
+}
+
+/* should be void (always returns 0) */
+static int maxpos_avg_stop( void *vseq, void *a, void *b ) {
+
+ pos_avg_t *seq = (pos_avg_t *) vseq;
+ pos_avg_t *master = (pos_avg_t *) a;
+
+ if( !master->occurrences ||
+ seq-> val > master-> val ){
+ master-> val= seq-> val;
+ master-> x_sum= seq-> x_sum;
+ master-> y_sum= seq-> y_sum;
+ master-> occurrences= seq-> occurrences;
+ }
+ else if( seq-> val == master-> val ){
+ master-> x_sum+= seq-> x_sum;
+ master-> y_sum+= seq-> y_sum;
+ master-> occurrences+= seq-> occurrences;
+ }
+ im_free( seq );
+ return 0;
+}
+
diff --git a/libvips/arithmetic/im_maxpos_vec.c b/libvips/arithmetic/im_maxpos_vec.c
new file mode 100644
index 00000000..5542a091
--- /dev/null
+++ b/libvips/arithmetic/im_maxpos_vec.c
@@ -0,0 +1,470 @@
+/* @(#) Find the coordinates and values of the n maxima of an image.
+ * @(#)
+ * @(#) int im_maxpos_vec(
+ * @(#) IMAGE *im,
+ * @(#) int *xpos,
+ * @(#) int *ypos,
+ * @(#) double *maxima,
+ * @(#) int n
+ * @(#) );
+ * @(#)
+ * @(#) Find the coordinates and values of the n minima of an image.
+ * @(#)
+ * @(#) int im_minpos_vec(
+ * @(#) IMAGE *im,
+ * @(#) int *xpos,
+ * @(#) int *ypos,
+ * @(#) double *minima,
+ * @(#) int n
+ * @(#) );
+ * @(#)
+ *
+ * Copyright: 2006, The Nottingham Trent University
+ * Copyright: 2006, Tom Vajzovic
+ *
+ * Author: Tom Vajzovic
+ *
+ * Written on: 2006-09-01
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+/** HEADERS **/
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /* HAVE_CONFIG_H */
+#include
+
+#include
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC */
+
+
+/** TYPE DEFINITIONS **/
+
+typedef struct {
+
+ int *xs;
+ int *ys;
+ double *vals;
+ int *ptrs;
+ int start;
+
+} maxpos_list;
+
+
+/** LOCAL FUNCTIONS DECLARATIONS **/
+
+static maxpos_list *maxpos_list_alloc( int n );
+static void maxpos_list_free( maxpos_list *list );
+
+static void maxpos_list_init( maxpos_list *list, int n );
+static void *maxpos_vec_start( IMAGE *unrequired, void *, void * );
+static int maxpos_vec_scan( REGION *reg, void *seq, void *, void * );
+static void add_to_maxpos_list( maxpos_list *list, int x, int y, double val );
+static int maxpos_vec_stop( void *seq, void *, void * );
+
+static void minpos_list_init( maxpos_list *list, int n );
+static void *minpos_vec_start( IMAGE *unrequired, void *, void * );
+static int minpos_vec_scan( REGION *reg, void *seq, void *, void * );
+static void add_to_minpos_list( maxpos_list *list, int x, int y, double val );
+static int minpos_vec_stop( void *seq, void *, void * );
+
+
+/** EXPORTED FUNCTIONS **/
+
+int im_maxpos_vec( IMAGE *im, int *xpos, int *ypos, double *maxima, int n ){
+#define FUNCTION_NAME "im_maxpos_vec"
+ /* number of sequences used is beyond my control at this level, but I note that */
+ /* efficiency decreases as more sequences are used - speed may still increase */
+
+ int result;
+ int *pointers= im_malloc( NULL, n * sizeof( int* ) );
+ maxpos_list master_list= { xpos, ypos, maxima, pointers, 0 };
+
+ if( im_pincheck( im ) )
+ return -1;
+
+ if( !pointers )
+ return -1;
+
+ if( ! ( im_isint( im ) || im_isfloat( im ) ) ){
+ im_error( FUNCTION_NAME, "%s", _( "scalar images only" ) );
+ return -1;
+ }
+
+ if( 1 != im-> Bands ){
+ im_error( FUNCTION_NAME, "%s", _( "single band images only" ) );
+ return -1;
+ }
+
+ if( IM_CODING_NONE != im-> Coding ){
+ im_error( FUNCTION_NAME, "%s", _( "uncoded images only" ) );
+ return -1;
+ }
+
+ if( ! xpos || ! ypos || ! maxima || n < 1 ){
+ im_error( FUNCTION_NAME, "%s", _( "invalid argument" ) );
+ return -1;
+ }
+
+ maxpos_list_init( &master_list, n );
+
+ result= im_iterate( im, maxpos_vec_start, maxpos_vec_scan, maxpos_vec_stop, &n, &master_list );
+
+ im_free( pointers );
+
+ return result;
+#undef FUNCTION_NAME
+}
+
+
+int im_minpos_vec( IMAGE *im, int *xpos, int *ypos, double *minima, int n ){
+#define FUNCTION_NAME "im_minpos_vec"
+ /* number of sequences used is beyond my control at this level, but I note that */
+ /* effeciency decreases as more sequences are used - speed may still increase */
+
+ int result;
+ int *pointers= im_malloc( NULL, n * sizeof( int* ) );
+ maxpos_list master_list= { xpos, ypos, minima, pointers, 0 };
+
+ if( im_pincheck( im ) )
+ return -1;
+
+ if( !pointers )
+ return -1;
+
+ if( ! ( im_isint( im ) || im_isfloat( im ) ) ){
+ im_error( FUNCTION_NAME, "%s", _( "scalar images only" ) );
+ return -1;
+ }
+
+ if( 1 != im-> Bands ){
+ im_error( FUNCTION_NAME, "%s", _( "single band images only" ) );
+ return -1;
+ }
+
+ if( IM_CODING_NONE != im-> Coding ){
+ im_error( FUNCTION_NAME, "%s", _( "uncoded images only" ) );
+ return -1;
+ }
+
+ if( ! xpos || ! ypos || ! minima || n < 1 ){
+ im_error( FUNCTION_NAME, "%s", _( "invalid argument" ) );
+ return -1;
+ }
+
+ minpos_list_init( &master_list, n );
+
+ result= im_iterate( im, minpos_vec_start, minpos_vec_scan, minpos_vec_stop, &n, &master_list );
+
+ im_free( pointers );
+
+ return result;
+#undef FUNCTION_NAME
+}
+
+
+/** LOCAL FUNCTION DEFINITIONS **/
+
+static maxpos_list *maxpos_list_alloc( int n ){
+
+ maxpos_list *list= im_malloc( NULL, sizeof( maxpos_list ) );
+
+ if( ! list )
+ return NULL;
+
+ list-> xs= im_malloc( NULL, 3 * n * sizeof( int ) );
+ list-> vals= im_malloc( NULL, n * sizeof( double ) );
+
+ if( ! list-> xs || ! list-> vals ){
+ im_free( list-> xs );
+ im_free( list-> vals );
+ im_free( list );
+ return NULL;
+ }
+ list-> ys= list-> xs + n;
+ list-> ptrs= list-> ys + n;
+
+ return list;
+}
+
+static void maxpos_list_free( maxpos_list *list ){
+ im_free( list-> xs );
+ im_free( list-> vals );
+ im_free( list );
+}
+
+
+static void maxpos_list_init( maxpos_list *list, int n ){
+ int i;
+
+ for( i= 0; i < n; ++i ){
+ list-> xs[ i ]= 0;
+ list-> ys[ i ]= 0;
+ list-> vals[ i ]= 0;
+ list-> ptrs[ i ]= i + 1;
+ }
+
+ list-> ptrs[ n - 1 ]= -1;
+ list-> start= 0;
+}
+
+static void *maxpos_vec_start( IMAGE *unrequired, void *a, void *b ){
+
+ int *n = (int *) a;
+ maxpos_list *list= maxpos_list_alloc( *n );
+
+ if( ! list )
+ return NULL;
+
+ maxpos_list_init( list, *n );
+
+ return list;
+}
+
+static int maxpos_vec_scan( REGION *reg, void *seq, void *a, void *b ){
+
+ maxpos_list *list = (maxpos_list *) seq;
+
+#define MAXPOS_VEC_SCAN( type ){ \
+ \
+ int y= reg-> valid. top; \
+ int x; \
+ int ymax= y + reg-> valid. height; \
+ int xmax= reg-> valid. left + reg-> valid. width; \
+ \
+ type *row= (type*)IM_REGION_ADDR( reg, reg-> valid. left, y ) - reg-> valid. left; \
+ size_t skip= IM_REGION_LSKIP( reg ) / sizeof( type ); \
+ \
+ for( ; y < ymax; ++y, row+= skip ) \
+ for( x= reg-> valid. left; x < xmax; ++x ) \
+ if( row[ x ] > list-> vals[ list-> start ] ) \
+ add_to_maxpos_list( list, x, y, row[ x ] ); \
+}
+
+ switch( reg-> im-> BandFmt ){
+ case IM_BANDFMT_UCHAR: MAXPOS_VEC_SCAN( guint8 ) break;
+ case IM_BANDFMT_CHAR: MAXPOS_VEC_SCAN( gint8 ) break;
+ case IM_BANDFMT_USHORT: MAXPOS_VEC_SCAN( guint16 ) break;
+ case IM_BANDFMT_SHORT: MAXPOS_VEC_SCAN( gint16 ) break;
+ case IM_BANDFMT_UINT: MAXPOS_VEC_SCAN( guint32 ) break;
+ case IM_BANDFMT_INT: MAXPOS_VEC_SCAN( gint32 ) break;
+ case IM_BANDFMT_FLOAT: MAXPOS_VEC_SCAN( float ) break;
+ case IM_BANDFMT_DOUBLE: MAXPOS_VEC_SCAN( double ) break;
+ }
+
+#undef MAXPOS_VEC_SCAN
+
+ return 0;
+}
+
+static void add_to_maxpos_list( maxpos_list *list, int x, int y, double val ){
+
+ int pointer= list-> start;
+
+ while( -1 != list-> ptrs[ pointer ] && val > list-> vals[ list-> ptrs[ pointer ] ] )
+ pointer= list-> ptrs[ pointer ];
+
+ list-> xs[ list-> start ]= x;
+ list-> ys[ list-> start ]= y;
+ list-> vals[ list-> start ]= val;
+
+ if( list-> start != pointer ){
+ /* we are adding mid-chain not at the very bottom */
+ int second= list-> ptrs[ list-> start ];
+
+ list-> ptrs[ list-> start ]= list-> ptrs[ pointer ];
+ list-> ptrs[ pointer ]= list-> start;
+ list-> start= second;
+ }
+}
+
+static int maxpos_vec_stop( void *seq, void *a, void *b ){
+
+ /* reverse list */
+
+ maxpos_list *list = (maxpos_list *) seq;
+ maxpos_list *master_list = (maxpos_list *) b;
+
+ int prev= -1;
+ int pointer= list-> start;
+
+ while( -1 != list-> ptrs[ pointer ] ){
+
+ int next= list-> ptrs[ pointer ];
+
+ list-> ptrs[ pointer ]= prev;
+ prev= pointer;
+ pointer= next;
+ }
+ list-> ptrs[ pointer ]= prev;
+ list-> start= pointer;
+
+ /* add to main list */
+
+ for( ; -1 != pointer; pointer= list-> ptrs[ pointer ] )
+ /* loop over all the ones found in this sequence */
+
+ if( list-> vals[ pointer ] > master_list-> vals[ master_list-> start ] )
+ add_to_maxpos_list( master_list, list-> xs[ pointer ], list-> ys[ pointer ], list-> vals[ pointer ] );
+ else
+ break;
+ /* since we are now high->low, if this one isn't big enough, none of the rest are */
+
+ maxpos_list_free( list );
+
+ return 0;
+}
+
+
+static void minpos_list_init( maxpos_list *list, int n ){
+ int i;
+
+ for( i= 0; i < n; ++i ){
+ list-> xs[ i ]= 0;
+ list-> ys[ i ]= 0;
+ list-> vals[ i ]= DBL_MAX;
+ list-> ptrs[ i ]= i + 1;
+ }
+
+ list-> ptrs[ n - 1 ]= -1;
+ list-> start= 0;
+}
+
+static void *minpos_vec_start( IMAGE *unrequired, void *a, void *b ){
+
+ int *n = (int *) a;
+ maxpos_list *list= maxpos_list_alloc( *n );
+
+ if( ! list )
+ return NULL;
+
+ minpos_list_init( list, *n );
+
+ return list;
+}
+
+static int minpos_vec_scan( REGION *reg, void *seq, void *a, void *b ){
+
+ maxpos_list *list = (maxpos_list *) seq;
+
+#define MINPOS_VEC_SCAN( type ){ \
+ \
+ int y= reg-> valid. top; \
+ int x; \
+ int ymax= y + reg-> valid. height; \
+ int xmax= reg-> valid. left + reg-> valid. width; \
+ \
+ type *row= (type*)IM_REGION_ADDR( reg, reg-> valid. left, y ) - reg-> valid. left; \
+ size_t skip= IM_REGION_LSKIP( reg ) / sizeof( type ); \
+ \
+ for( ; y < ymax; ++y, row+= skip ) \
+ for( x= reg-> valid. left; x < xmax; ++x ) \
+ if( row[ x ] < list-> vals[ list-> start ] ) \
+ add_to_minpos_list( list, x, y, row[ x ] ); \
+}
+
+ switch( reg-> im-> BandFmt ){
+ case IM_BANDFMT_UCHAR: MINPOS_VEC_SCAN( guint8 ) break;
+ case IM_BANDFMT_CHAR: MINPOS_VEC_SCAN( gint8 ) break;
+ case IM_BANDFMT_USHORT: MINPOS_VEC_SCAN( guint16 ) break;
+ case IM_BANDFMT_SHORT: MINPOS_VEC_SCAN( gint16 ) break;
+ case IM_BANDFMT_UINT: MINPOS_VEC_SCAN( guint32 ) break;
+ case IM_BANDFMT_INT: MINPOS_VEC_SCAN( gint32 ) break;
+ case IM_BANDFMT_FLOAT: MINPOS_VEC_SCAN( float ) break;
+ case IM_BANDFMT_DOUBLE: MINPOS_VEC_SCAN( double ) break;
+ }
+
+#undef MINPOS_VEC_SCAN
+
+ return 0;
+}
+
+static void add_to_minpos_list( maxpos_list *list, int x, int y, double val ){
+
+ int pointer= list-> start;
+
+ while( -1 != list-> ptrs[ pointer ] && val < list-> vals[ list-> ptrs[ pointer ] ] )
+ pointer= list-> ptrs[ pointer ];
+
+ list-> xs[ list-> start ]= x;
+ list-> ys[ list-> start ]= y;
+ list-> vals[ list-> start ]= val;
+
+ if( list-> start != pointer ){
+ /* we are adding mid-chain not at the very bottom */
+ int second= list-> ptrs[ list-> start ];
+
+ list-> ptrs[ list-> start ]= list-> ptrs[ pointer ];
+ list-> ptrs[ pointer ]= list-> start;
+ list-> start= second;
+ }
+}
+
+static int minpos_vec_stop( void *seq, void *a, void *b ){
+
+ /* reverse list */
+
+ maxpos_list *list = (maxpos_list *) seq;
+ maxpos_list *master_list = (maxpos_list *) b;
+ int prev= -1;
+ int pointer= list-> start;
+
+ while( -1 != list-> ptrs[ pointer ] ){
+
+ int next= list-> ptrs[ pointer ];
+
+ list-> ptrs[ pointer ]= prev;
+ prev= pointer;
+ pointer= next;
+ }
+ list-> ptrs[ pointer ]= prev;
+ list-> start= pointer;
+
+ /* add to main list */
+
+ for( ; -1 != pointer; pointer= list-> ptrs[ pointer ] )
+ /* loop over all the ones found in this sequence */
+
+ if( list-> vals[ pointer ] < master_list-> vals[ master_list-> start ] )
+ add_to_minpos_list( master_list, list-> xs[ pointer ], list-> ys[ pointer ], list-> vals[ pointer ] );
+ else
+ break;
+ /* since we are now high->low, if this one isn't big enough, none of the rest are */
+
+ maxpos_list_free( list );
+
+ return 0;
+}
+
diff --git a/libvips/arithmetic/im_measure.c b/libvips/arithmetic/im_measure.c
new file mode 100644
index 00000000..55460f86
--- /dev/null
+++ b/libvips/arithmetic/im_measure.c
@@ -0,0 +1,210 @@
+/* Analyse a grid of colour patches, producing a DOUBLEMASK of averages.
+ * Pass an IMAGE, an IMAGE_BOX, the number of horizontal and vertical
+ * patches, an array giving the numbers of the patches to measure (patches are
+ * numbered left-to-right, top-to-bottom) and the name we should give the
+ * output mask. Return a DOUBLEMASK in which rows are patches and columns are
+ * bands.
+ *
+ * Example: 6 band image of 4x2 block of colour patches.
+ *
+ * +---+---+---+---+
+ * | 1 | 2 | 3 | 4 |
+ * +---+---+---+---+
+ * | 5 | 6 | 7 | 8 |
+ * +---+---+---+---+
+ *
+ * Then call im_measure( im, box, 4, 2, { 2, 4 }, 2, "fred" ) makes a mask
+ * "fred" which has 6 columns, two rows. The first row contains the averages
+ * for patch 2, the second for patch 4.
+ *
+ * Modified:
+ * 19/8/94 JC
+ * - now uses doubles for addressing
+ * - could miss by up to h pixels previously!
+ * - ANSIfied
+ * - now issues warning if any deviations are greater than 20% of the
+ * mean
+ * 31/10/95 JC
+ * - more careful about warning for averages <0, or averages near zero
+ * - can get these cases with im_measure() of IM_TYPE_LAB images
+ * 28/10/02 JC
+ * - number bands from zero in error messages
+ * 7/7/04
+ * - works on labq
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* Measure into array.
+ */
+static int
+measure_patches( IMAGE *im, double *coeff, IMAGE_BOX *box,
+ int h, int v, int *sel, int nsel )
+{
+ IMAGE *tmp;
+ int patch;
+ IMAGE_BOX sub;
+ int i, j;
+ int m, n;
+ double avg, dev;
+
+ /* How large are the patches we are to measure?
+ */
+ double pw = (double) box->xsize / (double) h;
+ double ph = (double) box->ysize / (double) v;
+
+ /* Set up sub to be the size we need for a patch.
+ */
+ sub.xsize = (pw + 1) / 2;
+ sub.ysize = (ph + 1) / 2;
+
+ /* Loop through sel, picking out areas to measure.
+ */
+ for( j = 0, patch = 0; patch < nsel; patch++ ) {
+ /* Sanity check. Is the patch number sensible?
+ */
+ if( sel[patch] <= 0 || sel[patch] > h*v ) {
+ im_error( "im_measure",
+ _( "patch %d is out of range" ),
+ sel[patch] );
+ return( 1 );
+ }
+
+ /* Patch coordinates.
+ */
+ m = (sel[patch] - 1) % h;
+ n = (sel[patch] - 1) / h;
+
+ /* Move sub to correct position.
+ */
+ sub.xstart = box->xstart + m*pw + (pw + 2)/4;
+ sub.ystart = box->ystart + n*ph + (ph + 2)/4;
+
+ /* Loop through bands.
+ */
+ for( i = 0; i < im->Bands; i++, j++ ) {
+ /* Make temp buffer to extract to.
+ */
+ if( !(tmp = im_open( "patch", "t" )) )
+ return( -1 );
+
+ /* Extract and measure.
+ */
+ sub.chsel = i;
+ if( im_extract( im, tmp, &sub ) ||
+ im_avg( tmp, &avg ) ||
+ im_deviate( tmp, &dev ) ) {
+ im_close( tmp );
+ return( -1 );
+ }
+ im_close( tmp );
+
+ /* Is the deviation large compared with the average?
+ * This could be a clue that our parameters have
+ * caused us to miss the patch. Look out for averages
+ * <0, or averages near zero (can get these if use
+ * im_measure() on IM_TYPE_LAB images).
+ */
+ if( dev*5 > fabs( avg ) && fabs( avg ) > 3 )
+ im_warn( "im_measure",
+ _( "patch %d, band %d: "
+ "avg = %g, sdev = %g" ),
+ patch, i, avg, dev );
+
+ /* Save results.
+ */
+ coeff[j] = avg;
+ }
+ }
+
+ return( 0 );
+}
+
+/* Measure up image.
+ */
+DOUBLEMASK *
+im_measure( IMAGE *im, IMAGE_BOX *box, int h, int v,
+ int *sel, int nsel, const char *name )
+{
+ DOUBLEMASK *mask;
+
+ /* Check input image.
+ */
+ if( im->Coding == IM_CODING_LABQ ) {
+ IMAGE *t1;
+
+ if( !(t1 = im_open( "measure-temp", "p" )) )
+ return( NULL );
+ if( im_LabQ2Lab( im, t1 ) ||
+ !(mask = im_measure( t1,
+ box, h, v, sel, nsel, name )) ) {
+ im_close( t1 );
+ return( NULL );
+ }
+
+ im_close( t1 );
+
+ return( mask );
+ }
+
+ if( im->Coding != IM_CODING_NONE ) {
+ im_error( "im_measure", "%s", _( "not uncoded" ) );
+ return( NULL );
+ }
+ if( im_iscomplex( im ) ) {
+ im_error( "im_measure", "%s", _( "bad input type" ) );
+ return( NULL );
+ }
+
+ /* What size mask do we need?
+ */
+ if( !(mask = im_create_dmask( name, im->Bands, nsel )) )
+ return( NULL );
+
+ /* Perform measure and return.
+ */
+ if( measure_patches( im, mask->coeff, box, h, v, sel, nsel ) ) {
+ im_free_dmask( mask );
+ return( NULL );
+ }
+
+ return( mask );
+}
diff --git a/libvips/arithmetic/im_min.c b/libvips/arithmetic/im_min.c
new file mode 100644
index 00000000..55a76c70
--- /dev/null
+++ b/libvips/arithmetic/im_min.c
@@ -0,0 +1,246 @@
+/* @(#) Function to find the minimum of an image. Works for any
+ * @(#) image type. Returns a double.
+ * @(#)
+ * @(#) int im_min(in, min)
+ * @(#) IMAGE *in;
+ * @(#) double *min;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ *
+ * Copyright: 1990, J. Cupitt
+ *
+ * Author: J. Cupitt
+ * Written on: 02/05/1990
+ * Modified on : 18/03/1991, N. Dessipris
+ * 7/7/93 JC
+ * - complex case fixed
+ * - im_incheck() call added
+ * 20/6/95 JC
+ * - now returns double
+ * - modernised a little
+ * - now returns min square amplitude rather than amplitude for complex
+ * 9/5/02 JC
+ * - partialed, based in im_max()
+ * 3/4/02 JC
+ * - random wrong result for >1 thread :-( (thanks Joe)
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+/*
+#define DEBUG
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* Per-call state.
+ */
+typedef struct _MinInfo {
+ /* Parameters.
+ */
+ IMAGE *in;
+ double *out;
+
+ /* Global min so far.
+ */
+ double value;
+ int valid; /* zero means value is unset */
+} MinInfo;
+
+/* Per thread state.
+ */
+typedef struct _Seq {
+ MinInfo *inf;
+
+ double value;
+ int valid; /* zero means value is unset */
+} Seq;
+
+/* New sequence value.
+ */
+static void *
+start_fn( IMAGE *im, void *a, void *b )
+{
+ MinInfo *inf = (MinInfo *) a;
+ Seq *seq = IM_NEW( NULL, Seq );
+
+ seq->inf = inf;
+ seq->valid = 0;
+
+ return( seq );
+}
+
+/* Merge the sequence value back into the per-call state.
+ */
+static int
+stop_fn( void *vseq, void *a, void *b )
+{
+ Seq *seq = (Seq *) vseq;
+ MinInfo *inf = (MinInfo *) a;
+
+ if( seq->valid ) {
+ if( !inf->valid )
+ /* Just copy.
+ */
+ inf->value = seq->value;
+ else
+ /* Merge.
+ */
+ inf->value = IM_MIN( inf->value, seq->value );
+
+ inf->valid = 1;
+ }
+
+ im_free( seq );
+
+ return( 0 );
+}
+
+/* Loop over region, adding to seq.
+ */
+static int
+scan_fn( REGION *reg, void *vseq, void *a, void *b )
+{
+ Seq *seq = (Seq *) vseq;
+ Rect *r = ®->valid;
+ IMAGE *im = reg->im;
+ int le = r->left;
+ int to = r->top;
+ int bo = IM_RECT_BOTTOM(r);
+ int nel = IM_REGION_N_ELEMENTS( reg );
+
+ int x, y;
+
+ double m;
+
+#ifdef DEBUG
+ printf( "im_min: left = %d, top = %d, width = %d, height = %d\n",
+ r->left, r->top, r->width, r->height );
+#endif /*DEBUG*/
+
+#define loop(TYPE) { \
+ m = *((TYPE *) IM_REGION_ADDR( reg, le, to )); \
+ \
+ for( y = to; y < bo; y++ ) { \
+ TYPE *p = (TYPE *) IM_REGION_ADDR( reg, le, y ); \
+ \
+ for( x = 0; x < nel; x++ ) { \
+ double v = p[x]; \
+ \
+ if( v < m ) \
+ m = v; \
+ } \
+ } \
+}
+
+#define complex_loop(TYPE) { \
+ TYPE *p = (TYPE *) IM_REGION_ADDR( reg, le, to ); \
+ double real = p[0]; \
+ double imag = p[1]; \
+ \
+ m = real * real + imag * imag; \
+ \
+ for( y = to; y < bo; y++ ) { \
+ TYPE *p = (TYPE *) IM_REGION_ADDR( reg, le, y ); \
+ \
+ for( x = 0; x < nel * 2; x += 2 ) { \
+ double mod; \
+ \
+ real = p[x]; \
+ imag = p[x + 1]; \
+ mod = real * real + imag * imag; \
+ \
+ if( mod < m ) \
+ m = mod; \
+ } \
+ } \
+}
+
+ switch( im->BandFmt ) {
+ case IM_BANDFMT_UCHAR: loop( unsigned char ); break;
+ case IM_BANDFMT_CHAR: loop( signed char ); break;
+ case IM_BANDFMT_USHORT: loop( unsigned short ); break;
+ case IM_BANDFMT_SHORT: loop( signed short ); break;
+ case IM_BANDFMT_UINT: loop( unsigned int ); break;
+ case IM_BANDFMT_INT: loop( signed int ); break;
+ case IM_BANDFMT_FLOAT: loop( float ); break;
+ case IM_BANDFMT_DOUBLE: loop( double ); break;
+ case IM_BANDFMT_COMPLEX: complex_loop( float ); break;
+ case IM_BANDFMT_DPCOMPLEX: complex_loop( double ); break;
+
+ default:
+ assert( 0 );
+ }
+
+ if( seq->valid ) {
+ seq->value = IM_MIN( seq->value, m );
+ }
+ else {
+ seq->value = m;
+ seq->valid = 1;
+ }
+
+ return( 0 );
+}
+
+int
+im_min( IMAGE *in, double *out )
+{
+ MinInfo inf;
+
+ inf.in = in;
+ inf.out = out;
+ inf.valid = 0;
+
+ if( im_pincheck( in ) )
+ return( -1 );
+ if( in->Coding != IM_CODING_NONE ) {
+ im_error( "im_min", "%s", _( "not uncoded" ) );
+ return( -1 );
+ }
+
+ if( im_iterate( in, start_fn, scan_fn, stop_fn, &inf, NULL ) )
+ return( -1 );
+
+ *out = inf.value;
+
+ return( 0 );
+}
diff --git a/libvips/arithmetic/im_minpos.c b/libvips/arithmetic/im_minpos.c
new file mode 100644
index 00000000..6861d69a
--- /dev/null
+++ b/libvips/arithmetic/im_minpos.c
@@ -0,0 +1,143 @@
+/* @(#) Function to find the minimim of an image. Works for any
+ * @(#) image type. Returns a double and the location of min
+ * @(#)
+ * @(#) Function im_minpos() assumes that input
+ * @(#) is either memory mapped or in a buffer.
+ * @(#)
+ * @(#) int im_minpos(in, xpos, ypos, out)
+ * @(#) IMAGE *in;
+ * @(#) int *xpos, *ypos;
+ * @(#) double *out;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ *
+ * Copyright: 1990, J. Cupitt
+ *
+ * Author: J. Cupitt
+ * Written on: 02/05/1990
+ * Modified on : 18/03/1991, N. Dessipris
+ * 23/11/92 JC
+ * - correct result for more than 1 band now.
+ * 23/7/93 JC
+ * - im_incheck() added
+ * 20/6/95 JC
+ * - now returns double for value, like im_max()
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* Find the minimum of an image. Take any format, returns a double. */
+int
+im_minpos( IMAGE *in, int *xpos, int *ypos, double *out )
+{
+ double m;
+ int xp=0, yp=0;
+ int os;
+
+/* Check our args. */
+ if( im_incheck( in ) )
+ return( -1 );
+ if( in->Coding != IM_CODING_NONE )
+ {
+ im_error("im_minpos", "%s", _("input must be uncoded"));
+ return( -1 );
+ }
+
+/* What type? First define the loop we want to perform for all types. */
+#define loop(TYPE) \
+ { TYPE *p = (TYPE *) in->data; \
+ int x, y; \
+ m = (double) *p; \
+ \
+ for ( y=0; yYsize; y++ ) \
+ for ( x=0; xdata; \
+ double re=(double)*p;\
+ double im=(double)*(p+1);\
+ double mod = re * re + im * im;\
+ int x, y; \
+ m = mod; \
+ \
+ for ( y=0; yYsize; y++ ) \
+ for ( x=0; xXsize * in->Bands;
+ switch( in->BandFmt ) {
+ case IM_BANDFMT_UCHAR: loop(unsigned char); break;
+ case IM_BANDFMT_CHAR: loop(signed char); break;
+ case IM_BANDFMT_USHORT: loop(unsigned short); break;
+ case IM_BANDFMT_SHORT: loop(signed short); break;
+ case IM_BANDFMT_UINT: loop(unsigned int); break;
+ case IM_BANDFMT_INT: loop(signed int); break;
+ case IM_BANDFMT_FLOAT: loop(float); break;
+ case IM_BANDFMT_DOUBLE: loop(double); break;
+ case IM_BANDFMT_COMPLEX: loopcmplx(float); break;
+ case IM_BANDFMT_DPCOMPLEX: loopcmplx(double); break;
+
+ default:
+ assert( 0 );
+ }
+
+ /* Take out bands on x.
+ */
+ *out = m;
+ *xpos = xp / in->Bands;
+ *ypos = yp;
+ return( 0 );
+}
diff --git a/libvips/arithmetic/im_multiply.c b/libvips/arithmetic/im_multiply.c
new file mode 100644
index 00000000..7e2488cf
--- /dev/null
+++ b/libvips/arithmetic/im_multiply.c
@@ -0,0 +1,262 @@
+/* @(#) Multiply two images
+ * @(#) Images must have the same no of bands and can be of any type
+ * @(#) No check for overflow is carried out.
+ * @(#)
+ * @(#) int
+ * @(#) im_multiply(in1, in2, out)
+ * @(#) IMAGE *in1, *in2, *out;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ * @(#)
+ *
+ * Copyright: 1990, N. Dessipris.
+ *
+ * Author: Nicos Dessipris
+ * Written on: 02/05/1990
+ * Modified on:
+ * 29/4/93 JC
+ * - now works for partial images
+ * 1/7/93 JC
+ * - adapted for partial v2
+ * - ANSIfied
+ * 19/10/93 JC
+ * - coredump-inducing bug in complex*complex fixed
+ * 13/12/93
+ * - char*short bug fixed
+ * 12/6/95 JC
+ * - new im_add adapted to make new im_multiply
+ * 27/9/04
+ * - updated for 1 band $op n band image -> n band image case
+ * 8/12/06
+ * - add liboil support
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /*HAVE_CONFIG_H*/
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#ifdef HAVE_LIBOIL
+#include
+#endif /*HAVE_LIBOIL*/
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC*/
+
+/* Swap two IMAGE pointers.
+ */
+#define SWAP(A,B) { \
+ IMAGE *t; \
+ t = (A); (A) = (B); (B) = t; \
+}
+
+/* Complex multiply.
+ */
+#define cloop(TYPE) \
+{\
+ TYPE *p1 = (TYPE *) in[0];\
+ TYPE *p2 = (TYPE *) in[1];\
+ TYPE *q = (TYPE *) out;\
+ \
+ for( x = 0; x < sz; x++ ) {\
+ double x1 = p1[0];\
+ double y1 = p1[1];\
+ double x2 = p2[0];\
+ double y2 = p2[1];\
+ \
+ p1 += 2;\
+ p2 += 2;\
+ \
+ q[0] = x1 * x2 - y1 * y2;\
+ q[1] = x1 * y2 + x2 * y1;\
+ \
+ q += 2;\
+ }\
+}
+
+/* Real multiply.
+ */
+#define rloop(TYPE) \
+{\
+ TYPE *p1 = (TYPE *) in[0];\
+ TYPE *p2 = (TYPE *) in[1];\
+ TYPE *q = (TYPE *) out;\
+ \
+ for( x = 0; x < sz; x++ )\
+ q[x] = p1[x] * p2[x];\
+}
+
+static void
+multiply_buffer( PEL **in, PEL *out, int width, IMAGE *im )
+{
+ int x;
+ int sz = width * im->Bands;
+
+ /* Multiply all input types.
+ */
+ switch( im->BandFmt ) {
+ case IM_BANDFMT_CHAR: rloop( signed char ); break;
+ case IM_BANDFMT_UCHAR: rloop( unsigned char ); break;
+ case IM_BANDFMT_SHORT: rloop( signed short ); break;
+ case IM_BANDFMT_USHORT: rloop( unsigned short ); break;
+ case IM_BANDFMT_INT: rloop( signed int ); break;
+ case IM_BANDFMT_UINT: rloop( unsigned int ); break;
+
+ case IM_BANDFMT_FLOAT:
+#ifdef HAVE_LIBOIL
+ oil_multiply_f32( (float *) out,
+ (float *) in[0], (float *) in[1], sz );
+#else /*!HAVE_LIBOIL*/
+ rloop( float );
+#endif /*HAVE_LIBOIL*/
+ break;
+
+ case IM_BANDFMT_DOUBLE: rloop( double ); break;
+ case IM_BANDFMT_COMPLEX: cloop( float ); break;
+ case IM_BANDFMT_DPCOMPLEX: cloop( double ); break;
+
+ default:
+ assert( 0 );
+ }
+}
+
+/* Save a bit of typing.
+ */
+#define UC IM_BANDFMT_UCHAR
+#define C IM_BANDFMT_CHAR
+#define US IM_BANDFMT_USHORT
+#define S IM_BANDFMT_SHORT
+#define UI IM_BANDFMT_UINT
+#define I IM_BANDFMT_INT
+#define F IM_BANDFMT_FLOAT
+#define M IM_BANDFMT_COMPLEX
+#define D IM_BANDFMT_DOUBLE
+#define DM IM_BANDFMT_DPCOMPLEX
+
+/* Type conversions for two integer inputs. Rules for float and complex
+ * encoded with ifs. We are sign and value preserving.
+ */
+static int iformat[6][6] = {
+ /* UC C US S UI I */
+/* UC */ { US, S, UI, I, UI, I },
+/* C */ { S, S, I, I, I, I },
+/* US */ { UI, I, UI, I, UI, I },
+/* S */ { I, I, I, I, I, I },
+/* UI */ { UI, I, UI, I, UI, I },
+/* I */ { I, I, I, I, I, I }
+};
+
+int
+im_multiply( IMAGE *in1, IMAGE *in2, IMAGE *out )
+{
+ /* Basic checks.
+ */
+ if( im_piocheck( in1, out ) || im_pincheck( in2 ) )
+ return( -1 );
+
+ if( in1->Xsize != in2->Xsize || in1->Ysize != in2->Ysize ) {
+ im_error( "im_multiply", "%s", _( "not same size" ) );
+ return( -1 );
+ }
+ if( in1->Bands != in2->Bands &&
+ (in1->Bands != 1 && in2->Bands != 1) ) {
+ im_error( "im_multiply",
+ "%s", _( "not same number of bands" ) );
+ return( -1 );
+ }
+ if( in1->Coding != IM_CODING_NONE || in2->Coding != IM_CODING_NONE ) {
+ im_error( "im_multiply", "%s", _( "not uncoded" ) );
+ return( -1 );
+ }
+ if( im_cp_descv( out, in1, in2, NULL ) )
+ return( -1 );
+
+ /* What number of bands will we write?
+ */
+ out->Bands = IM_MAX( in1->Bands, in2->Bands );
+
+ /* Swap arguments to get the largest on the left.
+ */
+ if( in1->Bbits < in2->Bbits )
+ SWAP( in1, in2 );
+
+ /* What output type will we write? int, float or complex.
+ */
+ if( im_iscomplex( in1 ) || im_iscomplex( in2 ) ) {
+ /* Make sure we have complex on the left.
+ */
+ if( !im_iscomplex( in1 ) )
+ SWAP( in1, in2 );
+
+ /* What kind of complex?
+ */
+ if( in1->BandFmt == IM_BANDFMT_DPCOMPLEX )
+ /* Output will be DPCOMPLEX.
+ */
+ out->BandFmt = IM_BANDFMT_DPCOMPLEX;
+ else
+ out->BandFmt = IM_BANDFMT_COMPLEX;
+ }
+ else if( im_isfloat( in1 ) || im_isfloat( in2 ) ) {
+ /* Make sure we have float on the left.
+ */
+ if( !im_isfloat( in1 ) )
+ SWAP( in1, in2 );
+
+ /* What kind of float?
+ */
+ if( in1->BandFmt == IM_BANDFMT_DOUBLE )
+ out->BandFmt = IM_BANDFMT_DOUBLE;
+ else
+ out->BandFmt = IM_BANDFMT_FLOAT;
+ }
+ else
+ /* Must be int+int = int.
+ */
+ out->BandFmt = iformat[in2->BandFmt][in1->BandFmt];
+
+ /* And process!
+ */
+ if( im__cast_and_call( in1, in2, out,
+ (im_wrapmany_fn) multiply_buffer, NULL ) )
+ return( -1 );
+
+ /* Success!
+ */
+ return( 0 );
+}
diff --git a/libvips/arithmetic/im_point_bilinear.c b/libvips/arithmetic/im_point_bilinear.c
new file mode 100644
index 00000000..97169af6
--- /dev/null
+++ b/libvips/arithmetic/im_point_bilinear.c
@@ -0,0 +1,127 @@
+/* @(#) Find the value at (x,y) in given band of image.
+ * @(#) Use bilinear interpolation if x or y are non-integral.
+ * @(#)
+ * @(#) int im_maxpos_vec(
+ * @(#) IMAGE *im,
+ * @(#) double x,
+ * @(#) double y,
+ * @(#) int band,
+ * @(#) double *val
+ * @(#) );
+ * @(#)
+ *
+ * Copyright: 2006, The Nottingham Trent University
+ *
+ * Author: Tom Vajzovic
+ *
+ * Written on: 2006-09-26
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+/** HEADERS **/
+
+#ifdef HAVE_CONFIG_H
+#include
+#endif /* HAVE_CONFIG_H */
+#include
+
+#include
+#include
+
+#ifdef WITH_DMALLOC
+#include
+#endif /*WITH_DMALLOC */
+
+
+/** EXPORTED FUNCTION **/
+
+int im_point_bilinear( IMAGE *im, double x, double y, int band, double *val ){
+#define FUNCTION_NAME "im_point_bilinear"
+
+ double x_frac= x - (int) x;
+ double y_frac= y - (int) y;
+ Rect need= { x, y, ( x_frac ? 2 : 1 ), ( y_frac ? 2 : 1 ) };
+ REGION *reg;
+
+ if( im_pincheck( im ) )
+ return -1;
+
+ if( im-> Coding ){
+ im_error( FUNCTION_NAME, "%s", _("uncoded images only") );
+ return -1;
+ }
+ if( !( im_isint( im ) || im_isfloat( im ) ) ){
+ im_error( FUNCTION_NAME, "%s", _("scalar images only") );
+ return -1;
+ }
+ if( band >= im-> Bands || x < 0.0 || y < 0.0 || x > im-> Xsize || y > im-> Ysize ){
+ im_error( FUNCTION_NAME, "%s", _("coords outside image") );
+ return -1;
+ }
+ if( ! val ){
+ im_error( FUNCTION_NAME, "%s", _("invalid arguments") );
+ return -1;
+ }
+
+ reg= im_region_create( im );
+
+ if( ! reg || im_prepare( reg, &need ) )
+ return -1;
+
+ if( ! im_rect_includesrect( ®-> valid, &need ) ){
+ im_error( FUNCTION_NAME, "%s", _("coords outside image") );
+ im_region_free( reg );
+ return -1;
+ }
+
+ if( x_frac )
+ if( y_frac )
+ *val= x_frac * y_frac * (double) IM_REGION_VALUE( reg, ((int)x + 1), ((int)y + 1), band )
+ + x_frac * ( 1.0 - y_frac ) * (double) IM_REGION_VALUE( reg, ((int)x + 1), (int)y , band )
+ + ( 1.0 - x_frac ) * y_frac * (double) IM_REGION_VALUE( reg, (int)x, ((int)y + 1), band )
+ + ( 1.0 - x_frac ) * ( 1.0 - y_frac ) * (double) IM_REGION_VALUE( reg, (int)x, (int)y , band );
+
+ else
+ *val= x_frac * IM_REGION_VALUE( reg, ((int)x + 1), (int)y, band )
+ + ( 1.0 - x_frac ) * IM_REGION_VALUE( reg, (int)x, (int)y, band );
+
+ else
+ if( y_frac )
+ *val= y_frac * IM_REGION_VALUE( reg, (int)x, ((int)y + 1), band )
+ + ( 1.0 - y_frac ) * IM_REGION_VALUE( reg, (int)x, (int)y , band );
+
+ else
+ *val= IM_REGION_VALUE( reg, (int)x, (int)y, band );
+
+ im_region_free( reg );
+
+ return 0;
+
+#undef FUNCTION_NAME
+}
+
diff --git a/libvips/arithmetic/im_powtra.c b/libvips/arithmetic/im_powtra.c
new file mode 100644
index 00000000..49e1176d
--- /dev/null
+++ b/libvips/arithmetic/im_powtra.c
@@ -0,0 +1,235 @@
+/* @(#) Finds the power of an image
+ * @(#) Function im_powtra() assumes that the imin file
+ * @(#) is either memory mapped or in a buffer.
+ * @(#) Output image pow(imin, exponent) depends on input
+ * @(#) If input is up to float, output is float
+ * @(#) else input is the same as output
+ * @(#) Works on any number of bands.
+ * @(#)
+ * @(#) int im_powtra( in, out, e )
+ * @(#) IMAGE *in, *out;
+ * @(#) double e;
+ * @(#)
+ * @(#) Returns 0 on success and -1 on error
+ * @(#)
+ *
+ * Copyright: 1990, N. Dessipris
+ *
+ * Author: Nicos Dessipris
+ * Written on: 02/05/1990
+ * Modified on:
+ * 10/12/93 JC
+ * - now reports total number of x/0, rather than each one.
+ * 1/2/95 JC
+ * - rewritten for PIO with im_wrapone()
+ * - incorrect complex code removed
+ * - /0 reporting removed for ease of programming
+ * 15/4/97 JC
+ * - return( 0 ) missing, oops!
+ * 6/7/98 JC
+ * - _vec form added
+ */
+
+/*
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+
+/*
+
+ These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include