start final push for vips 8

This commit is contained in:
John Cupitt 2015-02-11 17:01:02 +00:00
parent 5b90e36559
commit 244ab301f7
52 changed files with 858 additions and 7480 deletions

View File

@ -1,3 +1,10 @@
11/2/15 started 8.0
- remove old doc stuff
- add fliphor(), flipver(), rot90(), rot180(), rot270() convenience methods to
Python
- add shift option to cast
- better alpha handling for 16 <-> 8 bit colour conversions
6/2/15 started 7.42.3
- bump version for back-compat ABI change
- added vips_image_memory(), an alias for vips_image_new_memory()

44
TODO
View File

@ -1,3 +1,41 @@
- at the moment we have a policy of just ignoring extra bands
we are proposing to change this to modify band 2, 4 or 5, if present, when
going to and from RGB16 or GREY16
if we make this change, we must support it for all transforms of this type,
not just for a couple, or it'll be incredibly confusing
vips_process_n() could use cast(shift = TRUE)
vips_colour_build() could use cast shift too
- use vips_sRGB2RGB16()
- check vips_sRGB2scRGB() with a 16-bit source ... what does it do for alpha?
alpha is untouched ... rgb->0-1, alpha stays at 0-65535
maybe should move everything to 0-1? otherwise when we do scRGB2sRGB we'll
(effectively) do alpha * 256
but what if we then do scRGB -> XYZ (for example), should alpha stay 0 - 1?
- we have
im.flip("horizontal")
maybe add fliphor() and flipver() as convenience functions, cf. .sin() etc.
- why can't we do
im = Vips.Image.new_from_file(sys.argv[1], access = "sequential")
@ -8,11 +46,11 @@
im.embed(10, 10, 100, 100, extend = "copy")
what about
- msb in colour should not touch alpha channel
im = Vips.Image.jpegload(sys.argv[1], access = "sequential")
... or should it? should converting RGBA from 8 to 16-bit touch alpha too?
probably
nope, fails too

View File

@ -13,15 +13,14 @@ 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/libvips-docs.xml.in poop ; \
mv reference/Makefile.am poop ; \
mv reference/images poop ; \
mv reference/*.xml poop ; \
mv reference/*.py poop ; \
rm -rf reference/* ; \
mv poop/* reference ; \
( mkdir poop ; \
mv doc/libvips-docs.xml.in poop ; \
mv doc/Makefile.am poop ; \
mv doc/images poop ; \
mv doc/*.xml poop ; \
mv doc/*.py poop ; \
rm -rf doc/* ; \
mv poop/* doc ; \
rmdir poop \
)
@ -45,7 +44,7 @@ cp $ACDIR/lcmessage.m4 m4
cp $ACDIR/progtest.m4 m4
cp $ACDIR/introspection.m4 m4
gtkdocize --copy --docdir doc/reference --flavour no-tmpl || exit 1
gtkdocize --copy --docdir doc --flavour no-tmpl || exit 1
# some systems need libtoolize, some glibtoolize ... how annoying
echo testing for glibtoolize ...

View File

@ -2,7 +2,7 @@
# also update the version number in the m4 macros below
AC_INIT([vips], [7.42.3], [vipsip@jiscmail.ac.uk])
AC_INIT([vips], [8.0.0], [vipsip@jiscmail.ac.uk])
# required for gobject-introspection
AC_PREREQ(2.62)
@ -16,9 +16,9 @@ AC_CONFIG_HEADERS(config.h)
AC_CONFIG_MACRO_DIR([m4])
# user-visible library versioning
m4_define([vips_major_version], [7])
m4_define([vips_minor_version], [42])
m4_define([vips_micro_version], [3])
m4_define([vips_major_version], [8])
m4_define([vips_minor_version], [0])
m4_define([vips_micro_version], [0])
m4_define([vips_version],
[vips_major_version.vips_minor_version.vips_micro_version])
@ -38,7 +38,7 @@ VIPS_VERSION_STRING=$VIPS_VERSION-`date`
# binary interface changes not backwards compatible?: reset age to 0
LIBRARY_CURRENT=41
LIBRARY_REVISION=0
LIBRARY_REVISION=1
LIBRARY_AGE=1
# patched into include/vips/version.h
@ -59,7 +59,7 @@ GOBJECT_INTROSPECTION_CHECK([1.30.0])
# gir needs a list of source files to scan for introspection
#
# build with a glob and a list of files to exclude from scanning
# see also IGNORE_HFILES in doc/reference/Makefile.am
# see also IGNORE_HFILES in doc/Makefile.am
introspection_sources=$(cd libvips ; find . -name "*.c")
filter_list="deprecated "
@ -839,8 +839,7 @@ AC_OUTPUT([
swig/vipsCC/Makefile
man/Makefile
doc/Makefile
doc/reference/Makefile
doc/reference/libvips-docs.xml
doc/libvips-docs.xml
po/Makefile.in
])

View File

@ -1,7 +1,187 @@
## Process this file with automake to produce Makefile.in
SUBDIRS = reference
# We require automake 1.6 at least.
AUTOMAKE_OPTIONS = 1.6
EXTRA_DIST = \
html \
pdf \
src
# 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=libvips
# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
#DOC_MODULE_VERSION=2
# The top-level XML file (SGML in the past). You can change this if you want to.
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml
# Directories containing the source code.
# gtk-doc will search all .c and .h files beneath these paths
# for inline comments documenting functions and macros.
# e.g. DOC_SOURCE_DIR=$(top_srcdir)/gtk $(top_srcdir)/gdk
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=--xml-mode --output-format=xml
MKDB_OPTIONS=--xml-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 or dirs to ignore when scanning. Use base file/dir names
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
IGNORE_VIPS_INCLUDE = \
almostdeprecated.h \
cimg_funcs.h \
deprecated.h \
vips7compat.h \
dispatch.h \
enumtypes.h \
internal.h \
thread.h \
intl.h \
format.h \
mask.h \
private.h \
video.h
# ignore all .h files in libvips/*, these are internal
IGNORE_VIPS_C = \
binary.h \
hough.h \
nary.h \
parithmetic.h \
statistic.h \
unaryconst.h \
unary.h \
CImg.h \
pcolour.h \
bandary.h \
pconversion.h \
correlation.h \
pconvolution.h \
pcreate.h \
pmask.h \
point.h \
drawink.h \
pdraw.h \
analyze2vips.h \
csv.h \
dbh.h \
fits.h \
jpeg.h \
magick.h \
matlab.h \
openexr2vips.h \
openslide2vips.h \
ppm.h \
radiance.h \
tiff.h \
vipsjpeg.h \
vipspng.h \
webp.h \
pfreqfilt.h \
hist_unary.h \
phistogram.h \
base64.h \
sink.h \
vipsmarshal.h \
pmorphology.h \
global_balance.h \
pmosaicing.h \
presample.h \
templates.h
IGNORE_HFILES = $(IGNORE_VIPS_INCLUDE) $(IGNORE_VIPS_C)
# Images to copy into HTML directory.
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
HTML_IMAGES = \
$(top_srcdir)/doc/images/interconvert.png
# 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 = \
using-command-line.xml \
using-C.xml \
using-python.xml \
using-cpp.xml \
extending.xml \
function-list.xml \
file-format.xml \
binding.xml
# 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 = \
using-command-line.xml \
using-C.xml \
using-python.xml \
using-cpp.xml \
extending.xml \
function-list.xml \
file-format.xml \
binding.xml
# 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)
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 gtk-doc.make
# Other files to distribute
# e.g. EXTRA_DIST += version.xml.in
EXTRA_DIST += \
images \
gen-function-list.py
# 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 = libvips.types
# Comment this out if you want 'make check' to test you doc status
# and run some sanity checks
if ENABLE_GTK_DOC
TESTS_ENVIRONMENT = \
DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \
SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir)
#TESTS = $(GTKDOC_CHECK)
endif
-include $(top_srcdir)/git.mk

289
doc/gtk-doc.make Normal file
View File

@ -0,0 +1,289 @@
# -*- mode: makefile -*-
####################################
# Everything below here is generic #
####################################
if GTK_DOC_USE_LIBTOOL
GTKDOC_CC = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(INCLUDES) $(GTKDOC_DEPS_CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
GTKDOC_LD = $(LIBTOOL) --tag=CC --mode=link $(CC) $(GTKDOC_DEPS_LIBS) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS)
GTKDOC_RUN = $(LIBTOOL) --mode=execute
else
GTKDOC_CC = $(CC) $(INCLUDES) $(GTKDOC_DEPS_CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
GTKDOC_LD = $(CC) $(GTKDOC_DEPS_LIBS) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS)
GTKDOC_RUN =
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)
SETUP_FILES = \
$(content_files) \
$(DOC_MAIN_SGML_FILE) \
$(DOC_MODULE)-sections.txt \
$(DOC_MODULE)-overrides.txt
EXTRA_DIST = \
$(HTML_IMAGES) \
$(SETUP_FILES)
DOC_STAMPS=setup-build.stamp scan-build.stamp sgml-build.stamp \
html-build.stamp pdf-build.stamp \
sgml.stamp html.stamp pdf.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
gtkdoc-check.test: Makefile
$(AM_V_GEN)echo "#!/bin/sh -e" > $@; \
echo "$(GTKDOC_CHECK_PATH) || exit 1" >> $@; \
chmod +x $@
CLEANFILES = $(SCANOBJ_FILES) $(REPORT_FILES) $(DOC_STAMPS) gtkdoc-check.test
if GTK_DOC_BUILD_HTML
HTML_BUILD_STAMP=html-build.stamp
else
HTML_BUILD_STAMP=
endif
if GTK_DOC_BUILD_PDF
PDF_BUILD_STAMP=pdf-build.stamp
else
PDF_BUILD_STAMP=
endif
all-gtk-doc: $(HTML_BUILD_STAMP) $(PDF_BUILD_STAMP)
.PHONY: all-gtk-doc
if ENABLE_GTK_DOC
all-local: all-gtk-doc
endif
docs: $(HTML_BUILD_STAMP) $(PDF_BUILD_STAMP)
$(REPORT_FILES): sgml-build.stamp
#### setup ####
GTK_DOC_V_SETUP=$(GTK_DOC_V_SETUP_$(V))
GTK_DOC_V_SETUP_=$(GTK_DOC_V_SETUP_$(AM_DEFAULT_VERBOSITY))
GTK_DOC_V_SETUP_0=@echo " DOC Preparing build";
setup-build.stamp:
-$(GTK_DOC_V_SETUP)if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \
files=`echo $(SETUP_FILES) $(expand_content_files) $(DOC_MODULE).types`; \
if test "x$$files" != "x" ; then \
for file in $$files ; do \
destdir=`dirname $(abs_builddir)/$$file`; \
test -d "$$destdir" || mkdir -p "$$destdir"; \
test -f $(abs_srcdir)/$$file && \
cp -pf $(abs_srcdir)/$$file $(abs_builddir)/$$file || true; \
done; \
fi; \
fi
$(AM_V_at)touch setup-build.stamp
#### scan ####
GTK_DOC_V_SCAN=$(GTK_DOC_V_SCAN_$(V))
GTK_DOC_V_SCAN_=$(GTK_DOC_V_SCAN_$(AM_DEFAULT_VERBOSITY))
GTK_DOC_V_SCAN_0=@echo " DOC Scanning header files";
GTK_DOC_V_INTROSPECT=$(GTK_DOC_V_INTROSPECT_$(V))
GTK_DOC_V_INTROSPECT_=$(GTK_DOC_V_INTROSPECT_$(AM_DEFAULT_VERBOSITY))
GTK_DOC_V_INTROSPECT_0=@echo " DOC Introspecting gobjects";
scan-build.stamp: setup-build.stamp $(HFILE_GLOB) $(CFILE_GLOB)
$(GTK_DOC_V_SCAN)_source_dir='' ; \
for i in $(DOC_SOURCE_DIR) ; do \
_source_dir="$${_source_dir} --source-dir=$$i" ; \
done ; \
gtkdoc-scan --module=$(DOC_MODULE) --ignore-headers="$(IGNORE_HFILES)" $${_source_dir} $(SCAN_OPTIONS) $(EXTRA_HFILES)
$(GTK_DOC_V_INTROSPECT)if grep -l '^..*$$' $(DOC_MODULE).types > /dev/null 2>&1 ; then \
scanobj_options=""; \
gtkdoc-scangobj 2>&1 --help | grep >/dev/null "\-\-verbose"; \
if test "$(?)" = "0"; then \
if test "x$(V)" = "x1"; then \
scanobj_options="--verbose"; \
fi; \
fi; \
CC="$(GTKDOC_CC)" LD="$(GTKDOC_LD)" RUN="$(GTKDOC_RUN)" CFLAGS="$(GTKDOC_CFLAGS) $(CFLAGS)" LDFLAGS="$(GTKDOC_LIBS) $(LDFLAGS)" \
gtkdoc-scangobj $(SCANGOBJ_OPTIONS) $$scanobj_options --module=$(DOC_MODULE); \
else \
for i in $(SCANOBJ_FILES) ; do \
test -f $$i || touch $$i ; \
done \
fi
$(AM_V_at)touch scan-build.stamp
$(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt: scan-build.stamp
@true
#### xml ####
GTK_DOC_V_XML=$(GTK_DOC_V_XML_$(V))
GTK_DOC_V_XML_=$(GTK_DOC_V_XML_$(AM_DEFAULT_VERBOSITY))
GTK_DOC_V_XML_0=@echo " DOC Building XML";
sgml-build.stamp: setup-build.stamp $(DOC_MODULE)-decl.txt $(SCANOBJ_FILES) $(DOC_MODULE)-sections.txt $(DOC_MODULE)-overrides.txt $(expand_content_files)
$(GTK_DOC_V_XML)_source_dir='' ; \
for i in $(DOC_SOURCE_DIR) ; do \
_source_dir="$${_source_dir} --source-dir=$$i" ; \
done ; \
gtkdoc-mkdb --module=$(DOC_MODULE) --output-format=xml --expand-content-files="$(expand_content_files)" --main-sgml-file=$(DOC_MAIN_SGML_FILE) $${_source_dir} $(MKDB_OPTIONS)
$(AM_V_at)touch sgml-build.stamp
sgml.stamp: sgml-build.stamp
@true
#### html ####
GTK_DOC_V_HTML=$(GTK_DOC_V_HTML_$(V))
GTK_DOC_V_HTML_=$(GTK_DOC_V_HTML_$(AM_DEFAULT_VERBOSITY))
GTK_DOC_V_HTML_0=@echo " DOC Building HTML";
GTK_DOC_V_XREF=$(GTK_DOC_V_XREF_$(V))
GTK_DOC_V_XREF_=$(GTK_DOC_V_XREF_$(AM_DEFAULT_VERBOSITY))
GTK_DOC_V_XREF_0=@echo " DOC Fixing cross-references";
html-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files)
$(GTK_DOC_V_HTML)rm -rf html && mkdir html && \
mkhtml_options=""; \
gtkdoc-mkhtml 2>&1 --help | grep >/dev/null "\-\-verbose"; \
if test "$(?)" = "0"; then \
if test "x$(V)" = "x1"; then \
mkhtml_options="$$mkhtml_options --verbose"; \
fi; \
fi; \
gtkdoc-mkhtml 2>&1 --help | grep >/dev/null "\-\-path"; \
if test "$(?)" = "0"; then \
mkhtml_options="$$mkhtml_options --path=\"$(abs_srcdir)\""; \
fi; \
cd html && gtkdoc-mkhtml $$mkhtml_options $(MKHTML_OPTIONS) $(DOC_MODULE) ../$(DOC_MAIN_SGML_FILE)
-@test "x$(HTML_IMAGES)" = "x" || \
for file in $(HTML_IMAGES) ; do \
if test -f $(abs_srcdir)/$$file ; then \
cp $(abs_srcdir)/$$file $(abs_builddir)/html; \
fi; \
if test -f $(abs_builddir)/$$file ; then \
cp $(abs_builddir)/$$file $(abs_builddir)/html; \
fi; \
done;
$(GTK_DOC_V_XREF)gtkdoc-fixxref --module=$(DOC_MODULE) --module-dir=html --html-dir=$(HTML_DIR) $(FIXXREF_OPTIONS)
$(AM_V_at)touch html-build.stamp
#### pdf ####
GTK_DOC_V_PDF=$(GTK_DOC_V_PDF_$(V))
GTK_DOC_V_PDF_=$(GTK_DOC_V_PDF_$(AM_DEFAULT_VERBOSITY))
GTK_DOC_V_PDF_0=@echo " DOC Building PDF";
pdf-build.stamp: sgml.stamp $(DOC_MAIN_SGML_FILE) $(content_files)
$(GTK_DOC_V_PDF)rm -f $(DOC_MODULE).pdf && \
mkpdf_options=""; \
gtkdoc-mkpdf 2>&1 --help | grep >/dev/null "\-\-verbose"; \
if test "$(?)" = "0"; then \
if test "x$(V)" = "x1"; then \
mkpdf_options="$$mkpdf_options --verbose"; \
fi; \
fi; \
if test "x$(HTML_IMAGES)" != "x"; then \
for img in $(HTML_IMAGES); do \
part=`dirname $$img`; \
echo $$mkpdf_options | grep >/dev/null "\-\-imgdir=$$part "; \
if test $$? != 0; then \
mkpdf_options="$$mkpdf_options --imgdir=$$part"; \
fi; \
done; \
fi; \
gtkdoc-mkpdf --path="$(abs_srcdir)" $$mkpdf_options $(DOC_MODULE) $(DOC_MAIN_SGML_FILE) $(MKPDF_OPTIONS)
$(AM_V_at)touch pdf-build.stamp
##############
clean-local:
@rm -f *~ *.bak
@rm -rf .libs
@if echo $(SCAN_OPTIONS) | grep -q "\-\-rebuild-types" ; then \
rm -f $(DOC_MODULE).types; \
fi
distclean-local:
@rm -rf xml html $(REPORT_FILES) $(DOC_MODULE).pdf \
$(DOC_MODULE)-decl-list.txt $(DOC_MODULE)-decl.txt
@if test "$(abs_srcdir)" != "$(abs_builddir)" ; then \
rm -f $(SETUP_FILES) $(expand_content_files) $(DOC_MODULE).types; \
fi
maintainer-clean-local:
@rm -rf xml html
install-data-local:
@installfiles=`echo $(builddir)/html/*`; \
if test "$$installfiles" = '$(builddir)/html/*'; \
then echo 1>&2 '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 ' $(INSTALL_DATA) '$$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; \
fi; \
$(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 HAVE_GTK_DOC
dist-check-gtkdoc: docs
else
dist-check-gtkdoc:
@echo "*** gtk-doc is needed to run 'make dist'. ***"
@echo "*** gtk-doc was not found when 'configure' ran. ***"
@echo "*** please install gtk-doc and rerun 'configure'. ***"
@false
endif
dist-hook: dist-check-gtkdoc all-gtk-doc dist-hook-local
@mkdir $(distdir)/html
@cp ./html/* $(distdir)/html
@-cp ./$(DOC_MODULE).pdf $(distdir)/
@-cp ./$(DOC_MODULE).types $(distdir)/
@-cp ./$(DOC_MODULE)-sections.txt $(distdir)/
@cd $(distdir) && rm -f $(DISTCLEANFILES)
@$(GTKDOC_REBASE) --online --relative --html-dir=$(distdir)/html
.PHONY : dist-hook-local docs

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

98
doc/libvips-docs.xml Normal file
View File

@ -0,0 +1,98 @@
<?xml version="1.0"?>
<!-- vim: set ts=2 sw=2 expandtab: -->
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
[
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
]>
<book id="index">
<bookinfo>
<title>VIPS Reference Manual</title>
<releaseinfo>
For VIPS 7.42.3.
The latest version of this documentation can be found on the
<ulink role="online-location"
url="http://www.vips.ecs.soton.ac.uk/index.php?title=Documentation">VIPS website</ulink>.
</releaseinfo>
</bookinfo>
<chapter>
<title>VIPS Overview</title>
<para>
VIPS is a free image processing system. It is good with large
images (images larger than the amount of RAM you have available), with
many CPUs (speed scales linearly to at least 32 threads), for working
with colour, for scientific analysis and for general research
and development. As well as JPEG, TIFF and PNG images, it also
supports scientific formats like FITS, Matlab, Analyze, PFM,
Radiance and OpenSlide. It works on many UNIX-like platforms,
as well as Windows and OS X. VIPS is released under the GNU Library
General Public License (GNU LGPL).
</para>
<xi:include href="xml/using-command-line.xml"/>
<xi:include href="xml/using-C.xml"/>
<xi:include href="xml/using-python.xml"/>
<xi:include href="xml/using-cpp.xml"/>
<xi:include href="xml/binding.xml"/>
<xi:include href="xml/extending.xml"/>
<xi:include href="xml/function-list.xml"/>
<xi:include href="xml/file-format.xml"/>
</chapter>
<chapter>
<title>Core VIPS API</title>
<xi:include href="xml/vips.xml"/>
<xi:include href="xml/image.xml"/>
<xi:include href="xml/header.xml"/>
<xi:include href="xml/generate.xml"/>
<xi:include href="xml/operation.xml"/>
<xi:include href="xml/error.xml"/>
<xi:include href="xml/memory.xml"/>
<xi:include href="xml/region.xml"/>
<xi:include href="xml/type.xml"/>
<xi:include href="xml/rect.xml"/>
<xi:include href="xml/object.xml"/>
<xi:include href="xml/threadpool.xml"/>
<xi:include href="xml/buf.xml"/>
<xi:include href="xml/basic.xml"/>
</chapter>
<chapter>
<title>VIPS operation API by section</title>
<xi:include href="xml/arithmetic.xml"/>
<xi:include href="xml/colour.xml"/>
<xi:include href="xml/conversion.xml"/>
<xi:include href="xml/convolution.xml"/>
<xi:include href="xml/foreign.xml"/>
<xi:include href="xml/freqfilt.xml"/>
<xi:include href="xml/histogram.xml"/>
<xi:include href="xml/draw.xml"/>
<xi:include href="xml/interpolate.xml"/>
<xi:include href="xml/morphology.xml"/>
<xi:include href="xml/mosaicing.xml"/>
<xi:include href="xml/create.xml"/>
<xi:include href="xml/resample.xml"/>
</chapter>
<chapter>
<title>Other API (no gtkdoc comments yet)</title>
<xi:include href="xml/transform.xml"/>
<xi:include href="xml/util.xml"/>
<xi:include href="xml/version.xml"/>
<xi:include href="xml/semaphore.xml"/>
</chapter>
<chapter id="object-tree">
<title>Object Hierarchy</title>
<xi:include href="xml/tree_index.sgml"/>
</chapter>
<index id="api-index-full">
<title>API Index</title>
<xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include>
<xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
</index>
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
</book>

View File

@ -1,187 +0,0 @@
## 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=libvips
# Uncomment for versioned docs and specify the version of the module, e.g. '2'.
#DOC_MODULE_VERSION=2
# The top-level XML file (SGML in the past). You can change this if you want to.
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml
# Directories containing the source code.
# gtk-doc will search all .c and .h files beneath these paths
# for inline comments documenting functions and macros.
# e.g. DOC_SOURCE_DIR=$(top_srcdir)/gtk $(top_srcdir)/gdk
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=--xml-mode --output-format=xml
MKDB_OPTIONS=--xml-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 or dirs to ignore when scanning. Use base file/dir names
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
IGNORE_VIPS_INCLUDE = \
almostdeprecated.h \
cimg_funcs.h \
deprecated.h \
vips7compat.h \
dispatch.h \
enumtypes.h \
internal.h \
thread.h \
intl.h \
format.h \
mask.h \
private.h \
video.h
# ignore all .h files in libvips/*, these are internal
IGNORE_VIPS_C = \
binary.h \
hough.h \
nary.h \
parithmetic.h \
statistic.h \
unaryconst.h \
unary.h \
CImg.h \
pcolour.h \
bandary.h \
pconversion.h \
correlation.h \
pconvolution.h \
pcreate.h \
pmask.h \
point.h \
drawink.h \
pdraw.h \
analyze2vips.h \
csv.h \
dbh.h \
fits.h \
jpeg.h \
magick.h \
matlab.h \
openexr2vips.h \
openslide2vips.h \
ppm.h \
radiance.h \
tiff.h \
vipsjpeg.h \
vipspng.h \
webp.h \
pfreqfilt.h \
hist_unary.h \
phistogram.h \
base64.h \
sink.h \
vipsmarshal.h \
pmorphology.h \
global_balance.h \
pmosaicing.h \
presample.h \
templates.h
IGNORE_HFILES = $(IGNORE_VIPS_INCLUDE) $(IGNORE_VIPS_C)
# Images to copy into HTML directory.
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
HTML_IMAGES = \
$(top_srcdir)/doc/reference/images/interconvert.png
# 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 = \
using-command-line.xml \
using-C.xml \
using-python.xml \
using-cpp.xml \
extending.xml \
function-list.xml \
file-format.xml \
binding.xml
# 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 = \
using-command-line.xml \
using-C.xml \
using-python.xml \
using-cpp.xml \
extending.xml \
function-list.xml \
file-format.xml \
binding.xml
# 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)
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 gtk-doc.make
# Other files to distribute
# e.g. EXTRA_DIST += version.xml.in
EXTRA_DIST += \
images \
gen-function-list.py
# 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 = libvips.types
# Comment this out if you want 'make check' to test you doc status
# and run some sanity checks
if ENABLE_GTK_DOC
TESTS_ENVIRONMENT = \
DOC_MODULE=$(DOC_MODULE) DOC_MAIN_SGML_FILE=$(DOC_MAIN_SGML_FILE) \
SRCDIR=$(abs_srcdir) BUILDDIR=$(abs_builddir)
#TESTS = $(GTKDOC_CHECK)
endif
-include $(top_srcdir)/git.mk

View File

@ -1,67 +0,0 @@
#
PDF = vipsmanual.pdf
SRC = \
applintro.tex \
cppintro.tex \
fileformat.tex \
func.tex \
format.tex \
iosys.tex \
ipio.tex \
mydefs.tex \
operintro.tex \
packages.tex \
pio.tex \
refintro.tex \
vdisplay.tex \
verror.tex \
vimage.tex \
vipsmanual.tex \
vmask.tex \
wio.tex
destdir = ../
all: $(PDF) html
install: all $(PDF) html
-rm -rf ${destdir}/pdf/*.pdf
-rm -rf ${destdir}/html/vips*
-rm -rf ${destdir}/html/figs
-mkdir -p ${destdir}/pdf
-mkdir -p ${destdir}/html
-cp $(PDF) ${destdir}/pdf
-cp -r vipsmanual/* ${destdir}/html
$(PDF): $(SRC)
pdflatex vipsmanual.tex
pdflatex vipsmanual.tex
.PHONY: html
html:
-rm -rf vipsmanual
mkdir vipsmanual
htlatex vipsmanual.tex html.cfg,3 "" -dvipsmanual/
cp -r figs vipsmanual
-rm vipsmanual/figs/*.svg
-rm vipsmanual/*.png
.PHONY: clean
clean:
-rm -f *.4ct
-rm -f *.4tc
-rm -f *.log
-rm -f *.xref
-rm -f *.tmp
-rm -f *.html
-rm -f *.css
-rm -f *.lg
-rm -f *.idv
-rm -f *.aux
-rm -f *.dvi
-rm -f *.lof
-rm -f *.lot
-rm -f *.toc
-rm -f *.pdf
-rm -rf vipsmanual

View File

@ -1,51 +0,0 @@
\section{Introduction}
\mylabel{sec:appl}
This chapter explains how to call VIPS functions from C programs. It does not
explain how to write new image processing operations (see \pref{sec:oper}),
only how to call the ones that VIPS provides. If you want to call VIPS
functions from C++ programs, you can either use the interface described here
or you can try out the much nicer C++ interface described in \pref{sec:cpp}.
See \pref{sec:ref} for an introduction to the image processing operations
available in the library. \fref{fg:architecture} tries to show
an overview of this structure.
\begin{fig2}
\figw{5in}{arch.png}
\caption{VIPS software architecture}
\label{fg:architecture}
\end{fig2}
VIPS includes a set of UNIX manual pages. Enter (for example):
\begin{verbatim}
example% man im_extract
\end{verbatim}
\noindent
to get an explanation of the \verb+im_extract()+ function.
All the command-line VIPS operations will print help text too. For example:
\begin{verbatim}
example% vips im_extract
usage: vips im_extract input output
left top width height band
where:
input is of type "image"
output is of type "image"
left is of type "integer"
top is of type "integer"
width is of type "integer"
height is of type "integer"
band is of type "integer"
extract area/band, from package
"conversion"
flags: (PIO function)
(coordinate transformer)
(area operation)
(result can be cached)
vips: error calling function
im_run_command: too few arguments
\end{verbatim}

View File

@ -1,108 +0,0 @@
\section{Introduction}
\mylabel{sec:cpp}
This chapter describes the C++ API for the VIPS image processing library.
The C++ API is as efficient as the C interface to VIPS, but is
far easier to use: almost all creation, destruction and error handling issues
are handled for you automatically.
The Python interface is a very simple wrapping of this C++ API generated
automatically with SWIG. It adds a few utility methods noted below, but
otherwise the two interfaces are identical other than language
syntax.
\subsection{If you've used the C API}
To show how much easier the VIPS C++ API is to use, compare \fref{fg:negative}
to \fref{fg:invert-c++}. \fref{fg:invert-py} is the same thing in Python.
A typical build line for the C++ program might be:
\begin{verbatim}
g++ invert.cc \
`pkg-config vipsCC-7.18 \
--cflags --libs`
\end{verbatim}
The key points are:
\begin{itemize}
\item
You just include \verb+<vips/vips>+ --- this then gets all of the
other includes you need. Everything is in the \verb+vips+ namespace.
\item
The C++ API replaces all of the VIPS C types --- \verb+IMAGE+ becomes
\verb+VImage+ and so on. The C++ API also includes \verb+VDisplay+,
\verb+VMask+ and \verb+VError+.
\item
Image processing operations are member functions of the \verb+VImage+ class
--- here, \verb+VImage( argv[1] )+ creates a new \verb+VImage+ object using
the first argument to initialise it (the input filename). It then calls the
member function \verb+invert()+, which inverts the \verb+VImage+ and returns a
new \verb+VImage+. Finally it calls the member function \verb+write()+, which
writes the result image to the named file.
\item
The VIPS C++ API uses exceptions --- the \verb+VError+ class is covered
later. If you run this program with a bad input file, for example, you get the
following output:
\begin{verbatim}
$ invert jim fred
invert: VIPS error: format_for_file:
file "jim" not found
\end{verbatim}
\end{itemize}
\begin{fig2}
\begin{verbatim}
#include <iostream>
#include <vips/vips>
int
main (int argc, char **argv)
{
if (argc != 3)
{
std::cerr << "usage: " << argv[0] << " infile outfile\n";
return (1);
}
try
{
vips::VImage fred (argv[1]);
fred.invert ().write (argv[2]);
}
catch (vips::VError e)
{
e.perror (argv[0]);
}
return (0);
}
\end{verbatim}
\caption{\texttt{invert} program in C++}
\label{fg:invert-c++}
\end{fig2}
\begin{fig2}
\begin{verbatim}
#!/usr/bin/python
import sys
from vipsCC import *
try:
a = VImage.VImage (sys.argv[1])
a.invert ().write (sys.argv[2])
except VError.VError, e:
e.perror (sys.argv[0])
\end{verbatim}
\caption{\texttt{invert} program in Python}
\label{fg:invert-py}
\end{fig2}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

View File

@ -1,385 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://web.resource.org/cc/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="744.09448819"
height="1052.3622047"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.44"
sodipodi:docbase="/home/john/CVS_DEVEL/vips-7.11/doc/src/figs"
sodipodi:docname="arch.svg"
inkscape:export-filename="/home/john/CVS_DEVEL/vips-7.11/doc/src/figs/arch.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs4">
<linearGradient
id="linearGradient3766">
<stop
style="stop-color:blue;stop-opacity:1;"
offset="0"
id="stop3768" />
<stop
style="stop-color:blue;stop-opacity:0;"
offset="1"
id="stop3770" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient3776"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.849266,0,0,0.598685,-15.86361,-14.13077)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient4785"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.849266,0,0,1.338534,0.3584,272.4737)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient4830"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-0.849266,0,0,1.338534,561.8794,272.4737)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient4854"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.599266,0,0,0.598685,36.9083,203.2571)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient4867"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.849266,0,0,0.598685,162.8669,201.2571)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient4869"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.849266,0,0,0.598685,162.8669,201.2571)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient4889"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.849266,0,0,1.13158,138.5445,237.5269)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient4908"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.849266,0,0,0.598685,162.8669,201.2571)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient4939"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.849266,0,0,0.598685,162.8669,201.2571)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient4953"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.849266,0,0,0.598685,162.8669,201.2571)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient4955"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.849266,0,0,0.598685,162.8669,201.2571)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient4960"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.84935,0,0,0.598685,-29.41424,440.032)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient5163"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.849266,0,0,1.338534,0.3584,272.4737)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient5172"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-0.849266,0,0,1.338534,561.8794,272.4737)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
gridtolerance="10000"
guidetolerance="10"
objecttolerance="10"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.6541113"
inkscape:cx="439.18963"
inkscape:cy="678.19429"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:window-width="1670"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="6"
showguides="true"
inkscape:guide-bbox="true" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
id="layer1"
inkscape:groupmode="layer">
<path
sodipodi:nodetypes="cccccccccccccc"
id="path4813"
d="M 465.26905,347.4375 C 474.21535,347.4375 481.4253,354.6162 481.4253,363.5625 L 481.4253,424.125 L 481.4253,440.8125 C 481.4253,449.7588 474.21535,456.9375 465.26905,456.9375 L 373.2378,456.9375 L 308.96873,456.9375 C 300.02243,456.9375 292.81247,449.75882 292.81248,440.8125 L 292.81248,424.125 C 292.81248,415.1787 300.02245,407.96875 308.96873,407.96875 L 357.08155,407.96875 L 357.08155,363.5625 C 357.08155,354.6162 364.2915,347.4375 373.2378,347.4375 L 465.26905,347.4375 z "
style="fill:url(#linearGradient5172);fill-opacity:1;stroke:black;stroke-width:2.30000257;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
style="fill:url(#linearGradient5163);fill-opacity:1;stroke:black;stroke-width:2.30000257;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 96.96875,347.4375 C 88.022452,347.4375 80.8125,354.6162 80.8125,363.5625 L 80.8125,424.125 L 80.8125,440.8125 C 80.8125,449.7588 88.022452,456.9375 96.96875,456.9375 L 189,456.9375 L 253.26907,456.9375 C 262.21537,456.9375 269.42533,449.75882 269.42532,440.8125 L 269.42532,424.125 C 269.42532,415.1787 262.21535,407.96875 253.26907,407.96875 L 205.15625,407.96875 L 205.15625,363.5625 C 205.15625,354.6162 197.9463,347.4375 189,347.4375 L 96.96875,347.4375 z "
id="rect4755"
sodipodi:nodetypes="cccccccccccccc" />
<path
style="fill:url(#linearGradient4889);fill-opacity:1;stroke:black;stroke-width:2.3000021;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 160.8539,280.5 C 151.9076,280.5 144.7289,287.70995 144.7289,296.65625 L 144.7289,313.34375 C 144.7289,322.29005 151.90761,329.46873 160.8539,329.46875 L 219,329.46875 L 219,377.34375 C 219,386.29005 226.20996,393.46876 235.15625,393.46875 L 327.1875,393.46875 C 336.1338,393.46875 343.34374,386.29006 343.34375,377.34375 L 343.34375,329.46875 L 400.95157,329.46875 C 409.89787,329.46875 417.07659,322.29004 417.07657,313.34375 L 417.07657,296.65625 C 417.07657,287.70995 409.89786,280.5 400.95157,280.5 L 160.8539,280.5 z "
id="rect4693"
sodipodi:nodetypes="ccccccccccccccc" />
<g
id="g4943"
transform="translate(4.079103,0)">
<g
transform="translate(-102.3224,-83.2251)"
id="g4667">
<rect
rx="16.148552"
ry="16.14856"
y="234.78189"
x="243.32465"
height="48.983932"
width="124.34397"
id="rect3778"
style="opacity:1;fill:url(#linearGradient4953);fill-opacity:1;stroke:black;stroke-width:2.30000234;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<text
id="text1972"
y="262.58441"
x="305.4527"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;opacity:1;fill:white;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="262.58441"
x="305.4527"
sodipodi:role="line"
id="tspan1974"
style="fill:white;fill-opacity:1;stroke:none">Python binding</tspan></text>
</g>
<g
transform="translate(-102.3224,-19.75669)"
id="g4686">
<rect
style="opacity:1;fill:url(#linearGradient4955);fill-opacity:1;stroke:black;stroke-width:2.30000234;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4674"
width="124.34397"
height="48.983932"
x="243.32465"
y="234.78189"
ry="16.14856"
rx="16.148552" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;opacity:1;fill:white;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
x="305.4527"
y="262.58441"
id="text4676"><tspan
style="fill:white;fill-opacity:1;stroke:none"
id="tspan4678"
sodipodi:role="line"
x="305.4527"
y="262.58441">C++ binding</tspan></text>
</g>
</g>
<text
id="text4788"
y="370.34372"
x="144.39862"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:white;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="370.34372"
x="144.39862"
sodipodi:role="line"
id="tspan4790"
style="fill:white;fill-opacity:1;stroke:none">VIPS image</tspan><tspan
y="385.34372"
x="144.39862"
sodipodi:role="line"
style="fill:white;fill-opacity:1;stroke:none"
id="tspan4792">processing</tspan><tspan
y="400.34372"
x="144.39862"
sodipodi:role="line"
style="fill:white;fill-opacity:1;stroke:none"
id="tspan4794">operations</tspan></text>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:white;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
x="418.38409"
y="370.34372"
id="text4815"><tspan
style="fill:white;fill-opacity:1;stroke:none"
id="tspan4817"
sodipodi:role="line"
x="418.38409"
y="370.34372">User image</tspan><tspan
id="tspan4819"
style="fill:white;fill-opacity:1;stroke:none"
sodipodi:role="line"
x="418.38409"
y="385.34372">processing</tspan><tspan
id="tspan4821"
style="fill:white;fill-opacity:1;stroke:none"
sodipodi:role="line"
x="418.38409"
y="400.34372">operations</tspan></text>
<rect
style="fill:url(#linearGradient4960);fill-opacity:1;stroke:black;stroke-width:2.30000234;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4836"
width="270.76959"
height="48.983932"
x="145.78938"
y="473.55679"
ry="16.14856"
rx="16.148552" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:white;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
x="281.13031"
y="501.35931"
id="text4838"><tspan
style="fill:white;fill-opacity:1;stroke:none"
id="tspan4840"
sodipodi:role="line"
x="281.13031"
y="501.35931">VIPS IO system</tspan></text>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:white;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
x="281.13031"
y="308.29611"
id="text4875"><tspan
style="fill:white;fill-opacity:1;stroke:none"
id="tspan4877"
sodipodi:role="line"
x="281.13031"
y="308.29611">Function dispatch</tspan></text>
<g
transform="translate(49.48783,-19.7567)"
id="g4900">
<g
id="g4924">
<rect
rx="16.148552"
ry="16.14856"
y="234.78189"
x="243.32465"
height="48.983932"
width="124.34397"
id="rect4902"
style="opacity:1;fill:url(#linearGradient4939);fill-opacity:1;stroke:black;stroke-width:2.30000234;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<text
id="text4904"
y="256.2475"
x="305.4527"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;opacity:1;fill:white;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="256.2475"
x="305.4527"
sodipodi:role="line"
id="tspan4906"
style="fill:white;fill-opacity:1;stroke:none">Command-line</tspan><tspan
id="tspan4922"
y="271.2475"
x="305.4527"
sodipodi:role="line"
style="fill:white;fill-opacity:1;stroke:none">interface</tspan></text>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,705 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="744.09448819"
height="1052.3622047"
id="svg2"
version="1.1"
inkscape:version="0.48.1 r9760"
sodipodi:docname="arch8.svg"
inkscape:export-filename="/home/john/Desktop/arch8.png"
inkscape:export-xdpi="72.058372"
inkscape:export-ydpi="72.058372">
<defs
id="defs4">
<linearGradient
inkscape:collect="always"
id="linearGradient3761">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop3763" />
<stop
style="stop-color:#bcb6e2;stop-opacity:1"
offset="1"
id="stop3765" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3761"
id="linearGradient4159"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.2402594,0,0,0.5194193,-67.40269,229.75711)"
x1="300.07144"
y1="285.21933"
x2="316.35712"
y2="637.71936" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3761"
id="linearGradient4161"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.2402594,0,0,0.5194193,-361.35709,227.73681)"
x1="300.07144"
y1="285.21933"
x2="316.35712"
y2="637.71936" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3761"
id="linearGradient4196"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.2402594,0,0,0.5194193,241.70399,220.66574)"
x1="300.07144"
y1="285.21933"
x2="316.35712"
y2="637.71936" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3761"
id="linearGradient4198"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.2402594,0,0,0.5194193,241.70399,138.66574)"
x1="300.07144"
y1="285.21933"
x2="316.35712"
y2="637.71936" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3761"
id="linearGradient4200"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.2402594,0,0,0.5194193,235.64308,29.49315)"
x1="300.07144"
y1="285.21933"
x2="316.35712"
y2="637.71936" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3761"
id="linearGradient4202"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.2402594,0,0,0.5194193,235.64308,-70.50685)"
x1="300.07144"
y1="285.21933"
x2="316.35712"
y2="637.71936" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3761"
id="linearGradient4241"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.2989487,0,0,1,-76.652343,113.13709)"
x1="300.07144"
y1="285.21933"
x2="316.35712"
y2="637.71936" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3761"
id="linearGradient4243"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.2989487,0,0,1,-76.407243,242.32127)"
x1="300.07144"
y1="285.21933"
x2="316.35712"
y2="637.71936" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3761"
id="linearGradient4586"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.2989487,0,0,1,-55.19404,250.40249)"
x1="300.07144"
y1="285.21933"
x2="316.35712"
y2="637.71936" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3761"
id="linearGradient4620"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.61835837,0,0,0.5194193,433.20773,-70.50685)"
x1="300.07144"
y1="285.21933"
x2="316.35712"
y2="637.71936" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3761"
id="linearGradient4622"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.61835837,0,0,0.5194193,433.20773,-70.50685)"
x1="300.07144"
y1="285.21933"
x2="316.35712"
y2="637.71936" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3761"
id="linearGradient4624"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.61835837,0,0,0.5194193,441.28895,6.462692)"
x1="300.07144"
y1="285.21933"
x2="316.35712"
y2="637.71936" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3761"
id="linearGradient4626"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.61835837,0,0,0.5194193,470.58338,124.88911)"
x1="300.07144"
y1="285.21933"
x2="316.35712"
y2="637.71936" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3761"
id="linearGradient4744"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.61835837,0,0,0.5194193,-501.18337,-0.62868109)"
x1="300.07144"
y1="285.21933"
x2="316.35712"
y2="637.71936" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3761"
id="linearGradient4746"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.61835837,0,0,0.5194193,-506.23414,78.34086)"
x1="300.07144"
y1="285.21933"
x2="316.35712"
y2="637.71936" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3761"
id="linearGradient4748"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.61835837,0,0,0.5194193,-528.4575,80.361165)"
x1="300.07144"
y1="285.21933"
x2="316.35712"
y2="637.71936" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="330.95697"
inkscape:cy="600.73181"
inkscape:document-units="px"
inkscape:current-layer="g4273"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1169"
inkscape:window-x="0"
inkscape:window-y="1"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g3862"
transform="matrix(0.53542698,0,0,0.53542698,147.94528,-56.775843)">
<rect
ry="19.871119"
y="560.14215"
x="196.12689"
height="114.28571"
width="279.73788"
id="rect2991"
style="fill:url(#linearGradient4241);fill-opacity:1;stroke:#000000;stroke-width:2.27942872;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<text
sodipodi:linespacing="125%"
id="text2987"
y="624.77911"
x="263.50848"
style="font-size:27.16452217px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="624.77911"
x="263.50848"
id="tspan2989"
sodipodi:role="line">VipsObject</tspan></text>
</g>
<g
id="g3867"
transform="matrix(0.53542698,0,0,0.53542698,147.81404,-57.327713)">
<rect
style="fill:url(#linearGradient4243);fill-opacity:1;stroke:#000000;stroke-width:2.27942872;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect3830"
width="279.73788"
height="114.28571"
x="196.37199"
y="689.32635"
ry="19.871119" />
<text
xml:space="preserve"
style="font-size:27.16452217px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
x="281.02985"
y="753.96332"
id="text3832"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3834"
x="281.02985"
y="753.96332">GObject</tspan></text>
</g>
<g
id="g3978"
transform="matrix(0.53542698,0,0,0.53542698,152.97543,-56.775843)">
<rect
ry="10.321443"
y="461.94016"
x="193.05182"
height="59.362209"
width="267.09872"
id="rect3915"
style="fill:url(#linearGradient4159);fill-opacity:1;stroke:#000000;stroke-width:1.60525966;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<text
sodipodi:linespacing="125%"
id="text3917"
y="499.11539"
x="252.69458"
style="font-size:27.16452217px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="499.11539"
x="252.69458"
id="tspan3919"
sodipodi:role="line">VipsRegion</tspan></text>
</g>
<g
id="g3968"
transform="matrix(0.53542698,0,0,0.53542698,149.73025,-55.694123)">
<rect
style="fill:url(#linearGradient4161);fill-opacity:1;stroke:#000000;stroke-width:1.60525966;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect3925"
width="267.09872"
height="59.362209"
x="-100.90259"
y="459.91986"
ry="10.321443" />
<text
xml:space="preserve"
style="font-size:27.16452217px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
x="-37.751518"
y="497.09509"
id="text3927"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3929"
x="-37.751518"
y="497.09509">VipsImage</tspan></text>
</g>
<g
id="g3988"
transform="matrix(0.53542698,0,0,0.53542698,148.10766,-51.908083)">
<rect
style="fill:url(#linearGradient4196);fill-opacity:1;stroke:#000000;stroke-width:1.60525966;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect3814"
width="267.09872"
height="59.362209"
x="502.15851"
y="452.84879"
ry="10.321443" />
<text
xml:space="preserve"
style="font-size:27.16452217px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
x="540.68512"
y="490.02402"
id="text3816"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3818"
x="540.68512"
y="490.02402">VipsOperation</tspan></text>
</g>
<g
id="g3998"
transform="matrix(0.53542698,0,0,0.53542698,148.10766,-59.970303)">
<rect
ry="10.321443"
y="370.84879"
x="502.15851"
height="59.362209"
width="267.09872"
id="rect3935"
style="fill:url(#linearGradient4198);fill-opacity:1;stroke:#000000;stroke-width:1.60525966;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<text
sodipodi:linespacing="125%"
id="text3937"
y="408.02402"
x="537.21655"
style="font-size:27.16452217px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="408.02402"
x="537.21655"
id="tspan3939"
sodipodi:role="line">VipsArithmetic</tspan></text>
</g>
<g
id="g4008"
transform="matrix(0.53542698,0,0,0.53542698,151.35284,-53.483543)">
<rect
style="fill:url(#linearGradient4200);fill-opacity:1;stroke:#000000;stroke-width:1.60525966;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect3945"
width="267.09872"
height="59.362209"
x="496.0976"
y="261.67621"
ry="10.321443" />
<text
xml:space="preserve"
style="font-size:27.16452217px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
x="557.81616"
y="298.85144"
id="text3947"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan3949"
x="557.81616"
y="298.85144">VipsBinary</tspan></text>
</g>
<g
id="g4018"
transform="matrix(0.53542698,0,0,0.53542698,151.35284,-51.908083)">
<rect
ry="10.321443"
y="161.67619"
x="496.0976"
height="59.362209"
width="267.09872"
id="rect3955"
style="fill:url(#linearGradient4202);fill-opacity:1;stroke:#000000;stroke-width:1.60525966;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<text
sodipodi:linespacing="125%"
id="text3957"
y="198.85143"
x="576.02087"
style="font-size:27.16452217px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="198.85143"
x="576.02087"
id="tspan3959"
sodipodi:role="line">VipsAdd</tspan></text>
</g>
<g
transform="translate(3.0304565,553.09137)"
id="g4220" />
<g
transform="translate(285.03046,369.09137)"
id="g4273">
<g
transform="matrix(0.53542698,0,0,0.53542698,21.269967,-426.46258)"
id="g4253">
<g
id="g4265"
transform="translate(-24,-8)">
<rect
style="fill:url(#linearGradient4586);fill-opacity:1;stroke:#000000;stroke-width:2.27942872;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect4255"
width="279.73788"
height="114.28571"
x="217.58521"
y="697.40759"
ry="19.871119" />
<text
xml:space="preserve"
style="font-size:27.16452217px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
x="357.3414"
y="745.06671"
id="text4257"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4259"
x="357.3414"
y="745.06671">GObject</tspan><tspan
id="tspan4263"
sodipodi:role="line"
x="357.3414"
y="779.02234">introspection</tspan></text>
</g>
</g>
<g
id="g4296"
transform="matrix(0.53542698,0,0,0.53542698,8.7894366,-175.82825)">
<g
id="g4283">
<rect
style="fill:url(#linearGradient4620);fill-opacity:1;stroke:#000000;stroke-width:1.13346767;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect4275"
width="133.16789"
height="59.362209"
x="563.06299"
y="161.67619"
ry="10.321443" />
<text
xml:space="preserve"
style="font-size:27.16452217px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
x="582.36768"
y="198.85141"
id="text4277"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4279"
x="582.36768"
y="198.85141">Python</tspan></text>
</g>
<g
id="g4288">
<rect
ry="10.321443"
y="161.67619"
x="563.06299"
height="59.362209"
width="133.16789"
id="rect4290"
style="fill:url(#linearGradient4622);fill-opacity:1;stroke:#000000;stroke-width:1.13346767;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<text
sodipodi:linespacing="125%"
id="text4292"
y="198.85141"
x="582.36768"
style="font-size:27.16452217px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="198.85141"
x="582.36768"
id="tspan4294"
sodipodi:role="line">Python</tspan></text>
</g>
</g>
<g
id="g4474"
transform="matrix(0.53542698,0,0,0.53542698,4.4625266,-170.40876)">
<rect
ry="10.321443"
y="238.64574"
x="571.14423"
height="59.362209"
width="133.16789"
id="rect4406"
style="fill:url(#linearGradient4624);fill-opacity:1;stroke:#000000;stroke-width:1.13346767;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<text
sodipodi:linespacing="125%"
id="text4408"
y="275.82095"
x="602.68488"
style="font-size:27.16452217px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="275.82095"
x="602.68488"
id="tspan4410"
sodipodi:role="line">Ruby</tspan></text>
</g>
<g
id="g4518"
transform="matrix(0.53542698,0,0,0.53542698,-11.222473,-187.18637)">
<rect
ry="10.321443"
y="357.07214"
x="600.4386"
height="59.362209"
width="133.16789"
id="rect4420"
style="fill:url(#linearGradient4626);fill-opacity:1;stroke:#000000;stroke-width:1.13346767;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<text
xml:space="preserve"
style="font-size:27.16452217px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
x="655.85431"
y="394.11472"
id="text4430"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4432"
x="655.85431"
y="394.11472">JS</tspan></text>
</g>
<flowRoot
xml:space="preserve"
id="flowRoot4438"
style="fill:black;stroke:none;stroke-opacity:1;stroke-width:1px;stroke-linejoin:miter;stroke-linecap:butt;fill-opacity:1;font-family:Bitstream Vera Sans;font-style:normal;font-weight:normal;font-size:12;line-height:125%;letter-spacing:0px;word-spacing:0px"><flowRegion
id="flowRegion4440"><rect
id="rect4442"
width="303.04578"
height="119.198"
x="772.76672"
y="495.76813" /></flowRegion><flowPara
id="flowPara4444"></flowPara></flowRoot> <g
id="g4697"
transform="matrix(0.53542698,0,0,0.53542698,17.312787,-183.26987)">
<g
transform="translate(18,-130)"
id="g4650">
<rect
ry="10.321443"
y="231.55435"
x="-371.32809"
height="59.362209"
width="133.16789"
id="rect4318"
style="fill:url(#linearGradient4744);fill-opacity:1;stroke:#000000;stroke-width:1.13346767;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
<text
sodipodi:linespacing="125%"
id="text4320"
y="268.72958"
x="-334.26965"
style="font-size:27.16452217px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="268.72958"
x="-334.26965"
id="tspan4322"
sodipodi:role="line">nip2</tspan></text>
</g>
<g
id="g4670"
transform="translate(23.05078,-126.47464)">
<rect
style="fill:url(#linearGradient4746);fill-opacity:1;stroke:#000000;stroke-width:1.13346767;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect4340"
width="133.16789"
height="59.362209"
x="-376.37888"
y="310.5239"
ry="10.321443" />
<text
xml:space="preserve"
style="font-size:27.16452217px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
x="-341.37634"
y="350.09326"
id="text4342"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4344"
x="-341.37634"
y="350.09326">C++</tspan></text>
</g>
<g
id="g4715"
transform="translate(45.274139,-46)">
<rect
style="fill:url(#linearGradient4748);fill-opacity:1;stroke:#000000;stroke-width:1.13346767;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="rect4699"
width="133.16789"
height="59.362209"
x="-398.60223"
y="312.54419"
ry="10.321443" />
<text
xml:space="preserve"
style="font-size:27.16452217px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
x="-352.51105"
y="352.11356"
id="text4701"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4703"
x="-352.51105"
y="352.11356">CLI</tspan></text>
</g>
<flowRoot
xml:space="preserve"
id="flowRoot4707"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
transform="translate(-285.03046,-453.09137)"><flowRegion
id="flowRegion4709"><rect
id="rect4711"
width="140.41121"
height="40.406101"
x="-71.720833"
y="795.78345" /></flowRegion><flowPara
id="flowPara4713"></flowPara></flowRoot> <path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 64.870258,590.88976 192.79316,603.49865"
id="path4762"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#g4650"
inkscape:connection-start-point="d4"
inkscape:connection-end="#g3862"
inkscape:connection-end-point="d4"
transform="translate(-285.03046,-453.09137)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 64.870257,656.95753 192.79316,638.00615"
id="path4764"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#g4670"
inkscape:connection-start-point="d4"
inkscape:connection-end="#g3862"
inkscape:connection-end-point="d4"
transform="translate(-285.03046,-453.09137)" />
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 62.858848,723.81955 199.81731,669.74012"
id="path4766"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#g4715"
inkscape:connection-start-point="d4"
inkscape:connection-end="#g3862"
inkscape:connection-end-point="d4"
transform="translate(-285.03046,-453.09137)" />
</g>
<path
style="fill:none;stroke:#000000;stroke-width:0.53542697px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 310.35527,-62.020015 -46.8051,14.937961"
id="path4785"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#g4296"
inkscape:connection-start-point="d4"
inkscape:connection-end="#g4253"
inkscape:connection-end-point="d4" />
<path
style="fill:none;stroke:#000000;stroke-width:0.53542697px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 310.26855,-26.739329 -46.71838,1e-6"
id="path4787"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#g4474"
inkscape:connection-start-point="d4"
inkscape:connection-end="#g4253"
inkscape:connection-end-point="d4" />
<path
style="fill:none;stroke:#000000;stroke-width:0.53542697px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 310.35527,8.5413745 262.82856,-6.6268942"
id="path4789"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#g4518"
inkscape:connection-start-point="d4"
inkscape:connection-end="#g4253"
inkscape:connection-end-point="d4" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

View File

@ -1,505 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://web.resource.org/cc/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="744.09448819"
height="1052.3622047"
id="svg1431"
sodipodi:version="0.32"
inkscape:version="0.43"
sodipodi:docbase="/home/john/CVS_DEVEL/vips-7.11/doc/src/figs"
sodipodi:docname="interconvert.svg"
inkscape:export-filename="/home/john/CVS_DEVEL/vips-7.11/doc/src/figs/interconvert.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
id="defs1433">
<marker
inkscape:stockid="Arrow1Mend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Mend"
style="overflow:visible;">
<path
id="path2732"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
transform="scale(0.4) rotate(180)" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Mstart"
style="overflow:visible">
<path
id="path2735"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
transform="scale(0.4)" />
</marker>
<marker
inkscape:stockid="Arrow1Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lend"
style="overflow:visible;">
<path
id="path2738"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
transform="scale(0.8) rotate(180)" />
</marker>
<marker
inkscape:stockid="Arrow1Lstart"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Lstart"
style="overflow:visible">
<path
id="path2741"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
transform="scale(0.8)" />
</marker>
<linearGradient
id="linearGradient3766">
<stop
style="stop-color:blue;stop-opacity:1;"
offset="0"
id="stop3768" />
<stop
style="stop-color:blue;stop-opacity:0;"
offset="1"
id="stop3770" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient1473"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.849266,0,0,0.598685,247.81,161.7982)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient1533"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.849266,0,0,0.598685,247.81,161.7982)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient1543"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.849266,0,0,0.598685,247.81,161.7982)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient1553"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.849266,0,0,0.598685,247.81,161.7982)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient1599"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.849266,0,0,0.598685,247.81,161.7982)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient1601"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.849266,0,0,0.598685,247.81,161.7982)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient1619"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.849266,0,0,0.598685,247.81,161.7982)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient1635"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.849266,0,0,0.598685,247.81,161.7982)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3766"
id="linearGradient2757"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.849266,0,0,0.598685,16.7937,60.4338)"
x1="158.72054"
y1="0.55397713"
x2="158.86745"
y2="185.72389" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.3548828"
inkscape:cx="276.197"
inkscape:cy="811.45446"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:window-width="917"
inkscape:window-height="766"
inkscape:window-x="721"
inkscape:window-y="190" />
<metadata
id="metadata1436">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<g
id="g1468"
transform="translate(-145.6376,-17.86691)">
<rect
rx="21.578072"
ry="20.801611"
y="195.32306"
x="328.2677"
height="41.603222"
width="43.156143"
id="rect4674"
style="fill:url(#linearGradient1473);fill-opacity:1;stroke:#000000;stroke-width:2.30000234;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<text
id="text4676"
y="220.5983"
x="349.58502"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="220.5983"
x="349.58502"
sodipodi:role="line"
id="tspan4678"
style="fill:#ffffff;fill-opacity:1;stroke:none">Lab</tspan></text>
</g>
<g
transform="translate(-61.37789,49.49029)"
id="g1475">
<rect
style="fill:url(#linearGradient1599);fill-opacity:1;stroke:#000000;stroke-width:2.30000234;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1477"
width="43.156143"
height="41.603222"
x="328.2677"
y="195.32306"
ry="20.801611"
rx="21.578072" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
x="349.58502"
y="220.5983"
id="text1479"><tspan
style="fill:#ffffff;fill-opacity:1;stroke:none"
id="tspan1481"
sodipodi:role="line"
x="349.58502"
y="220.5983">XYZ</tspan></text>
</g>
<g
id="g1505"
transform="translate(-61.37789,-85.22411)">
<rect
rx="21.578072"
ry="20.801611"
y="195.32306"
x="328.2677"
height="41.603222"
width="43.156143"
id="rect1507"
style="fill:url(#linearGradient1601);fill-opacity:1;stroke:#000000;stroke-width:2.30000234;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<text
id="text1509"
y="220.5983"
x="349.58502"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="220.5983"
x="349.58502"
sodipodi:role="line"
id="tspan1511"
style="fill:#ffffff;fill-opacity:1;stroke:none">LCh</tspan></text>
</g>
<g
transform="translate(22.88186,5.077526)"
id="g1525">
<rect
style="fill:url(#linearGradient1533);fill-opacity:1;stroke:#000000;stroke-width:2.30000234;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1527"
width="43.156143"
height="41.603222"
x="328.2677"
y="195.32306"
ry="20.801611"
rx="21.578072" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
x="349.58502"
y="220.5983"
id="text1529"><tspan
style="fill:#ffffff;fill-opacity:1;stroke:none"
id="tspan1531"
sodipodi:role="line"
x="349.58502"
y="220.5983">disp</tspan></text>
</g>
<g
id="g1535"
transform="translate(22.88186,95.37916)">
<rect
rx="21.578072"
ry="20.801611"
y="195.32306"
x="328.2677"
height="41.603222"
width="43.156143"
id="rect1537"
style="fill:url(#linearGradient1543);fill-opacity:1;stroke:#000000;stroke-width:2.30000234;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<text
id="text1539"
y="220.5983"
x="349.58502"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="220.5983"
x="349.58502"
sodipodi:role="line"
id="tspan1541"
style="fill:#ffffff;fill-opacity:1;stroke:none">Yxy</tspan></text>
</g>
<g
transform="translate(22.88186,-85.22411)"
id="g1545">
<rect
style="fill:url(#linearGradient1553);fill-opacity:1;stroke:#000000;stroke-width:2.30000234;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1547"
width="43.156143"
height="41.603222"
x="328.2677"
y="195.32306"
ry="20.801611"
rx="21.578072" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
x="349.58502"
y="220.5983"
id="text1549"><tspan
style="fill:#ffffff;fill-opacity:1;stroke:none"
id="tspan1551"
sodipodi:role="line"
x="349.58502"
y="220.5983">UCS</tspan></text>
</g>
<g
id="g2759">
<rect
rx="21.578072"
ry="20.801611"
y="93.958656"
x="97.251404"
height="41.603222"
width="43.156143"
id="rect1487"
style="fill:url(#linearGradient2757);fill-opacity:1;stroke:#000000;stroke-width:2.30000234;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<text
id="text1489"
y="119.23389"
x="118.56873"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="119.23389"
x="118.56873"
sodipodi:role="line"
id="tspan1491"
style="fill:#ffffff;fill-opacity:1;stroke:none">LabQ</tspan></text>
</g>
<g
transform="translate(-231.0163,-17.86691)"
id="g1495">
<rect
style="fill:url(#linearGradient1619);fill-opacity:1;stroke:#000000;stroke-width:2.30000234;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect1497"
width="43.156143"
height="41.603222"
x="328.2677"
y="195.32306"
ry="20.801611"
rx="21.578072" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
x="349.58502"
y="220.5983"
id="text1499"><tspan
style="fill:#ffffff;fill-opacity:1;stroke:none"
id="tspan1501"
sodipodi:role="line"
x="349.58502"
y="220.5983">LabS</tspan></text>
</g>
<g
id="g1555"
transform="translate(-231.0163,65.63058)">
<rect
rx="21.578072"
ry="20.801611"
y="195.32306"
x="328.2677"
height="41.603222"
width="43.156143"
id="rect1557"
style="fill:url(#linearGradient1635);fill-opacity:1;stroke:#000000;stroke-width:2.30000234;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<text
id="text1559"
y="220.5983"
x="349.58502"
style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
y="220.5983"
x="349.58502"
sodipodi:role="line"
id="tspan1561"
style="fill:#ffffff;fill-opacity:1;stroke:none">ICC</tspan></text>
</g>
<path
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:0.9;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Mstart);marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none"
d="M 141.55754,198.25776 L 181.4801,198.25776"
id="path1639"
inkscape:connector-type="polyline"
inkscape:connection-start="#g1495"
inkscape:connection-end="#g1468" />
<path
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:0.9;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Mstart);marker-mid:none;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none"
d="M 181.76199,220.20937 L 141.27566,259.80364"
id="path1645"
inkscape:connector-type="polyline"
inkscape:connection-start="#g1468"
inkscape:connection-end="#g1555" />
<path
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:0.9;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Mstart);marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none"
d="M 181.76199,176.30615 L 141.27566,136.71188"
id="path1647"
inkscape:connector-type="polyline"
inkscape:connection-start="#g1468" />
<path
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:0.9;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Mstart);marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none"
d="M 226.93624,216.42658 L 265.73981,247.44614"
id="path1685"
inkscape:connector-type="polyline"
inkscape:connection-start="#g1468"
inkscape:connection-end="#g1475" />
<path
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:0.9;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Mstart);marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none"
d="M 226.93624,180.08894 L 265.73981,149.06938"
id="path1687"
inkscape:connector-type="polyline"
inkscape:connection-start="#g1468"
inkscape:connection-end="#g1505" />
<path
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:0.9;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Mstart);marker-mid:none;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none"
d="M 311.19595,130.90056 L 349.99956,130.90056"
id="path1689"
inkscape:connector-type="polyline"
inkscape:connection-start="#g1505"
inkscape:connection-end="#g1545" />
<path
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:0.9;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Mstart);marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none"
d="M 311.19595,253.63514 L 349.99956,233.18201"
id="path1691"
inkscape:connector-type="polyline"
inkscape:connection-start="#g1475"
inkscape:connection-end="#g1525" />
<path
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:0.9;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow1Mstart);marker-end:url(#Arrow1Mend);marker-mid:none;stroke-miterlimit:4;stroke-dasharray:none"
d="M 311.19595,277.99294 L 349.99956,299.12585"
id="path1693"
inkscape:connector-type="polyline"
inkscape:connection-start="#g1475"
inkscape:connection-end="#g1535" />
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
x="408.81937"
y="224.40727"
id="text2764"><tspan
sodipodi:role="line"
id="tspan2766"
x="408.81937"
y="224.40727">Any VIPS RGB space</tspan></text>
<text
id="text2768"
y="326.40729"
x="94.858322"
style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
xml:space="preserve"
sodipodi:linespacing="125%"><tspan
y="326.40729"
x="94.858322"
id="tspan2770"
sodipodi:role="line">Any device with</tspan><tspan
y="341.40729"
x="94.858322"
sodipodi:role="line"
id="tspan2772">an ICC profile</tspan></text>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,173 +0,0 @@
\section{The VIPS file format}
VIPS has its own very simple file format. It is used inside VIPS to hold
images during computation. You can save images in VIPS format if you want,
but the VIPS format is not widely used and you may have problems reading
your images into other packages.
If you intend to keep an image, it's much better to save it as TIFF,
JPEG, PNG, PBM/PGM/PPM or HDR. VIPS can transparently read and write all
these formats.
\subsection{VIPS file header}
\label{sec:header}
All VIPS image files start with a 64-byte header giving basic information
about the image dimensions, see \tref{fg:header}. This is followed by the
image data. This is usually just the pixel values in native format (ie. the
byte order used by the machine that wrote the file) laid out left-to-right and
top-to-bottom. After the image data comes a block of optional XML which holds
extra image metadata, such as ICC profiles and image history.
You can use the command-line program \verb+header+ to extract the XML from an
image and \verb+edvips+ to replace it, see the man pages.
The \ct{Type} field, the \ct{Xres}/\ct{Yres} fields, and the
\ct{Xoffset}/\ct{Yoffset} fields are advisory. VIPS maintains their value
(if you convert an image to \cielab{} colour space with \ct{im\_XYZ2Lab()},
for example, VIPS will set \ct{Type} to be \ct{IM\_TYPE\_LAB}), but never
uses these values itself in determining the action of an image processing
function. These fields are to help the user and to help application
programs built on VIPS which are trying to present image data to the user
in a meaningful way.
The \ct{BandFmt}, \ct{Coding} and \ct{Type} fields can take the values
shown in tables~\ref{fg:bandfmt}, \ref{fg:coding} and \ref{fg:type}. The C++
and Python names for these values are slightly different, for historical
reasons.
\begin{tab2}
\begin{center}
\begin{tabular}{|l|l|l|}
\hline
Bytes & Represent & VIPS name \\
\hline
0--3 & VIPS magic number (in hex, 08 f2 f6 b6) & \\
4--7 & Number of pels per horizontal line (integer) & \ct{Xsize} \\
8--11 & Number of horizontal lines (integer) & \ct{Ysize} \\
12--15 & Number of bands (integer) & \ct{Bands} \\
16--19 & Unused (legacy) & \ct{Bbits} \\
20--23 & Band format (eg. \ct{IM\_BANDFMT\_USHORT}) & \ct{BandFmt} \\
24--27 & Coding type (eg. \ct{IM\_CODING\_NONE}) & \ct{Coding} \\
28--31 & Type (eg. \ct{IM\_TYPE\_LAB}) & \ct{Type} \\
32--35 & Horizontal resolution (float, pixels mm$^{-1}$) & \ct{Xres} \\
36--39 & Vertical resolution (float, pixels mm$^{-1}$) & \ct{Yres} \\
40--43 & Unused (legacy) & \ct{Length} \\
44--45 & Unused (legacy) & \ct{Compression} \\
46--47 & Unused (legacy) & \ct{Level} \\
48--51 & Horizontal offset of origin & \ct{Xoffset} \\
52--55 & Vertical offset of origin & \ct{Yoffset} \\
56--63 & For future expansion (all zeros for now) & \\
\hline
\end{tabular}
\end{center}
\caption{VIPS header\label{fg:header}}
\end{tab2}
\begin{tab2}
\begin{center}
\begin{tabular}{|l|l|l|l|}
\hline
\ct{BandFmt} & C++ and Python name & Value & Meaning \\
\hline
\ct{IM\_BANDFMT\_NOTSET} & \ct{FMTNOTSET} & -1 & \\
\ct{IM\_BANDFMT\_UCHAR} & \ct{FMTUCHAR} & 0 & Unsigned 8-bit int \\
\ct{IM\_BANDFMT\_CHAR} & \ct{FMTCHAR} & 1 & Signed 8-bit int \\
\ct{IM\_BANDFMT\_USHORT} & \ct{FMTUSHORT} & 2 & Unsigned 16-bit int \\
\ct{IM\_BANDFMT\_SHORT} & \ct{FMTSHORT} & 3 & Signed 16-bit int \\
\ct{IM\_BANDFMT\_UINT} & \ct{FMTUINT} & 4 & Unsigned 32-bit int \\
\ct{IM\_BANDFMT\_INT} & \ct{FMTINT} & 5 & Signed 32-bit int \\
\ct{IM\_BANDFMT\_FLOAT} & \ct{FMTFLOAT} & 6 & 32-bit IEEE float \\
\ct{IM\_BANDFMT\_COMPLEX} & \ct{FMTCOMPLEX} & 7 & Complex (2 floats) \\
\ct{IM\_BANDFMT\_DOUBLE} & \ct{FMTDOUBLE} & 8 & 64-bit IEEE double \\
\ct{IM\_BANDFMT\_DPCOMPLEX} & \ct{FMTDPCOMPLEX} & 9 & Complex (2 doubles) \\
\hline
\end{tabular}
\end{center}
\caption{Possible values for \ct{BandFmt}\label{fg:bandfmt}}
\end{tab2}
\begin{tab2}
\begin{center}
\begin{tabular}{|l|l|l|l|}
\hline
\ct{Coding} & C++ and Python name & Value & Meaning \\
\hline
\ct{IM\_CODING\_NONE} & \ct{NOCODING} & 0 & VIPS computation format \\
\ct{IM\_CODING\_LABQ} & \ct{LABQ} & 2 & LABQ storage format \\
\ct{IM\_CODING\_RAD} & \ct{RAD} & 6 & Radiance storage format \\
\hline
\end{tabular}
\end{center}
\caption{Possible values for \texttt{Coding}\label{fg:coding}}
\end{tab2}
\begin{tab2}
\begin{center}
\begin{tabular}{|l|l|l|l|}
\hline
\ct{Type} & C++ and Python name & Value & Meaning \\
\hline
\ct{IM\_TYPE\_MULTIBAND} & \ct{MULTIBAND} & 0 & Some multiband image \\
\ct{IM\_TYPE\_B\_W} & \ct{B\_W} & 1 & Some single band image \\
\ct{IM\_TYPE\_HISTOGRAM} & \ct{HISTOGRAM} & 10 & Histogram or LUT \\
\ct{IM\_TYPE\_FOURIER} & \ct{FOURIER} & 24 & Image in Fourier space \\
\ct{IM\_TYPE\_XYZ} & \ct{XYZ} & 12 & \ciexyz{} colour space \\
\ct{IM\_TYPE\_LAB} & \ct{LAB} & 13 & \cielab{} colour space \\
\ct{IM\_TYPE\_CMYK} & \ct{CMYK} & 15 & \ct{im\_icc\_export()} \\
\ct{IM\_TYPE\_LABQ} & \ct{LABQ} & 16 & 32-bit \cielab{} \\
\ct{IM\_TYPE\_RGB} & \ct{RGB} & 17 & Some RGB \\
\ct{IM\_TYPE\_UCS} & \ct{UCS} & 18 & \cieucs{} colour space \\
\ct{IM\_TYPE\_LCH} & \ct{LCH} & 19 & \cielch{} colour space \\
\ct{IM\_TYPE\_LABS} & \ct{LABS} & 21 & 48-bit \cielab{} \\
\ct{IM\_TYPE\_sRGB} & \ct{sRGB} & 22 & sRGB colour space \\
\ct{IM\_TYPE\_YXY} & \ct{YXY} & 23 & \cieyxy{} colour space \\
\ct{IM\_TYPE\_RGB16} & \ct{RGB16} & 25 & 16-bit RGB \\
\ct{IM\_TYPE\_GREY16} & \ct{GREY16} & 26 & 16-bit monochrome \\
\hline
\end{tabular}
\end{center}
\caption{Possible values for \texttt{Type}\label{fg:type}}
\end{tab2}
\subsection{Computation formats}
This type of image has \ct{Coding} set to \ct{IM\_CODING\_NONE}. The
header is then followed by a large array of pixels, laid out left-to-right,
top-to-bottom. Each pixel contains the specified number of bands. Each band
has the specified band format, which may be an 8-, 16- or 32-bit integer
(either signed or unsigned), a single or double precision IEEE floating
point number, or a pair of single or double precision floats forming a
complex number.
All values are stored in the host-machine's native number representation (that
is, either most-significant first, as in SPARC and 680x0 machines, or
least-significant first, for Intel and DEC machines). If necessary, the VIPS
library will automatically byte-swap for you during read.
\subsection{Storage formats}
All storage formats have other values for the \ct{Coding} field. This
release supports \ct{IM\_CODING\_LABQ} and \ct{IM\_CODING\_RAD}.
\ct{IM\_CODING\_LABQ} stores $L^{*}$, $a^{*}$ and $b^{*}$ for each pixel,
with 10 bits for $L^{*}$ and 11 bits for each of $a^{*}$ and $b^{*}$. These
32 bits are packed into 4 bytes, with the most significant 8 bits of each
value in the first 3 bytes, and the left-over bits packed into the final
byte as 2:3:3.
This format is a little awkward to process. Some VIPS functions can work
directly on \ct{IM\_CODING\_LABQ} images (\ct{im\_extract\_area()}, for
example), but most will require you to unpack the image to one of the
computation formats (for example with \ct{im\_LabQ2Lab()}) first.
\ct{IM\_CODING\_RAD} stores $RGB$ or $XYZ$ float images as 8 bytes of mantissa
and then 8 bytes of exponent, shared between the three channels. This coding
style is used by the Radiance family of programs (and the HDR format) commonly
used for HDR imaging. This style of image is generated when you load an HDR
image.
This format is a little awkward to process. Some VIPS functions can work
directly on \ct{IM\_CODING\_RAD} images (\ct{im\_extract\_area()}, for
example), but most will require you to unpack the image to one of the
computation formats with \ct{im\_rad2float()} first.

View File

@ -1,133 +0,0 @@
\section{Image formats}
\label{sec:format}
VIPS has a simple system for adding support for new image file formats.
You can ask VIPS to find a format to load a file with or to select a image
file writer based on a filename. Convenience functions copy a file to an
\verb+IMAGE+, or an \verb+IMAGE+ to a file. New formats may be added to
VIPS by simply defining a new subclass of \verb+VipsFormat+.
This is a parallel API to \verb+im_open()+, see \pref{sec:open}. The
format system is useful for images which are large or slow to open,
because you pass a descriptor to write to and so control how and where
the decompressed image is held. \verb+im_open()+ is useful for images in
formats which can be directly read from disc, since you will avoid a copy
operation and can directly control the disc file. The inplace operations
(see \pref{sec:inplace}), for example, will only work directly on disc
images if you use \verb+im_open()+.
\subsection{How a format is represented}
See the man page for \verb+VipsFormat+ for full details, but briefly, an image
format consists of the following items:
\begin{itemize}
\item
A name, a name that can be shows to the user, and a list of possible filename
suffixes (\verb+.tif+, for example)
\item
A function which tests for a file being in that format, a function which loads
just the header of the file (that is, it reads properties like width and
height and does not read any pixel data) and a function which loads the pixel
data
\item
A function which will write an \verb+IMAGE+ to a file in the format
\item
And finally a function which examines a file in the format and returns flags
indicating how VIPS should deal with the file. The only flag in the current
version is one indicating that the file can be opened lazily
\end{itemize}
\subsection{The format class}
The interface to the format system is defined by the abstract base class
\verb+VipsFormat+. Formats subclass this and implement some or all of the
methods. Any of the functions may be left NULL and VIPS will try to make do
with what you do supply. Of course a format with all functions as NULL will
not be very useful.
As an example, \fref{fg:newformat} shows how to register a new format in a
plugin.
\begin{fig2}
\begin{verbatim}
static const char *my_suffs[] = { ".me", NULL };
static int
is_myformat( const char *filename )
{
unsigned char buf[2];
if( im__get_bytes( filename, buf, 2 ) &&
(int) buf[0] == 0xff &&
(int) buf[1] == 0xd8 )
return( 1 );
return( 0 );
}
// This format adds no new members.
typedef VipsFormat VipsFormatMyformat;
typedef VipsFormatClass VipsFormatMyformatClass;
static void
vips_format_myformat_class_init( VipsFormatMyformatClass *class )
{
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsFormatClass *format_class = (VipsFormatClass *) class;
object_class->nickname = "myformat";
object_class->description = _( "My format" );
format_class->is_a = is_myformat;
format_class->header = my_header;
format_class->load = my_read;
format_class->save = my_write;
format_class->get_flags = my_get_flags;
format_class->priority = 100;
format_class->suffs = my_suffs;
}
static void
vips_format_myformat_init( VipsFormatMyformat *object )
{
}
G_DEFINE_TYPE( VipsFormatMyformat, vips_format_myformat, VIPS_TYPE_FORMAT );
char *
g_module_check_init( GModule *self )
{
// register the type
vips_format_myformat_get_type();
}
\end{verbatim}
\caption{Registering a format in a plugin}
\label{fg:newformat}
\end{fig2}
\subsection{Finding a format}
You can loop over the subclasses of \verb+VipsFormat+ in order of priority
with \verb+vips_format_map()+. Like all the map functions in VIPS, this take
a function and applies it to every element in the table until the function
returns non-zero or until the table ends.
You find an \verb+VipsFormatClass+ to use to open a file with
\verb+vips_format_for_file()+. This finds the first format whose \verb+is_a()+
function returns true or whose suffix list matches the suffix of the filename,
setting an error message and returning NULL if no format is found.
You find a format to write a file with \verb+vips_format_for_name()+. This
returns the first format with a save function whose suffix list matches the
suffix of the supplied filename.
\subsection{Convenience functions}
A pair of convenience functions, \verb+vips_format_write()+ and
\verb+vips_format_read()+, will copy an image to and from disc using the
appropriate format.

View File

@ -1,697 +0,0 @@
\section{Function dispatch and plug-ins}
(This chapter is on the verge of being deprecated. We have started building a
replacement based on \verb+GObject+, see \pref{sec:object}.)
As image processing libraries increase in size it becomes progressively more
difficult to build applications which present the operations the library
offers to the user. Every time a new operation is added, every user interface
needs to be adapted --- a job which can rapidly become unmanageable.
To address this problem VIPS includes a simple database which stores an
abstract description of every image processing operation. User interfaces,
rather than having special code wired into them for each operation, can
simply interrogate the database and present what they find to the user.
The operation database is extensible. You can define new operations, and even
new types, and add them to VIPS. These new operations will then automatically
appear in all VIPS user interfaces with no extra programming effort. Plugins
can extend the database at runtime: when VIPS starts, it loads all the plugins
in the VIPS library area.
\subsection{Simple plugin example}
As an example, consider this function:
\begin{verbatim}
#include <stdio.h>
#include <vips/vips.h>
/* The function we define. Call this
* from other parts of your C
* application.
*/
int
double_integer( int in )
{
return( in * 2 );
}
\end{verbatim}
\noindent
The source for all the example code in this section is in the vips-examples
package.
The first step is to make a layer over this function which will make it
look like a standard VIPS function. VIPS insists on the following pattern:
\begin{itemize}
\item
The function should be int-valued, and return 0 for success and non-zero
for error. It should set \verb+im_error()+.
\item
The function should take a single argument: a pointer to a
\verb+NULL+-terminated array of \verb+im_objects+.
\item
Each \verb+im_object+ represents one argument to the function (either output
or input) in the form specified by the corresponding entry in the function's
argument descriptor.
\end{itemize}
The argument descriptor is an array of structures, each describing one
argument. For this example, it is:
\begin{verbatim}
/* Describe the type of our function.
* One input int, and one output int.
*/
static im_arg_desc arg_types[] = {
IM_INPUT_INT( "in" ),
IM_OUTPUT_INT( "out" )
};
\end{verbatim}
\verb+IM_INPUT_INT()+ and \verb+IM_OUTPUT_INT()+ are macros defined in
\verb+<vips/dispatch.h>+ which make argument types easy to define. Other
macros available are listed in table~\ref{tab:type}.
\begin{tab2}
\begin{center}
\begin{tabular}{|l|l|l|}
\hline
Macro & Meaning &
\texttt{im\_object} has type \\
\hline
\texttt{IM\_INPUT\_INT} & Input int &
\texttt{int *} \\
\texttt{IM\_INPUT\_INTVEC} & Input vector of int &
\texttt{im\_intvec\_object *} \\
\texttt{IM\_INPUT\_IMASK} & Input int array &
\texttt{im\_mask\_object *} \\
\texttt{IM\_OUTPUT\_INT} & Output int &
\texttt{int *} \\
\texttt{IM\_INPUT\_INTVEC} & Output vector of int &
\texttt{im\_intvec\_object *} \\
\texttt{IM\_OUTPUT\_IMASK} & Output int array to file &
\texttt{im\_mask\_object *} \\
\texttt{IM\_INPUT\_DOUBLE} & Input double &
\texttt{double *} \\
\texttt{IM\_INPUT\_DOUBLEVEC} & Input vector of double &
\texttt{im\_realvec\_object *} \\
\texttt{IM\_INPUT\_DMASK} & Input double array &
\texttt{im\_mask\_object *} \\
\texttt{IM\_OUTPUT\_DOUBLE} & Output double &
\texttt{double *} \\
\texttt{IM\_OUTPUT\_DOUBLEVEC} & Output vector of double &
\texttt{im\_realvec\_object *} \\
\texttt{IM\_OUTPUT\_DMASK} & Output double array to file &
\texttt{im\_mask\_object *} \\
\texttt{IM\_OUTPUT\_DMASK\_STATS}& Output double array to screen &
\\
\texttt{IM\_OUTPUT\_COMPLEX} & Output complex &
\texttt{double *} \\
\texttt{IM\_INPUT\_STRING} & Input string &
\texttt{char *} \\
\texttt{IM\_OUTPUT\_STRING} & Output string &
\texttt{char *} \\
\texttt{IM\_INPUT\_IMAGE} & Input image &
\texttt{IMAGE *} \\
\texttt{IM\_INPUT\_IMAGEVEC} & Vector of input images &
\texttt{IMAGE **} \\
\texttt{IM\_OUTPUT\_IMAGE} & Output image &
\texttt{IMAGE *} \\
\texttt{IM\_RW\_IMAGE} & Read-write image &
\texttt{IMAGE *} \\
\texttt{IM\_INPUT\_DISPLAY} & Input display &
\texttt{im\_col\_display *} \\
\texttt{IM\_OUTPUT\_DISPLAY} & Output display &
\texttt{im\_col\_display *} \\
\texttt{IM\_INPUT\_GVALUE} & Input GValue &
\texttt{GValue *} \\
\texttt{IM\_OUTPUT\_GVALUE} & Output GValue &
\texttt{GValue *} \\
\texttt{IM\_INPUT\_INTERPOLATE} & Input VipsInterpolate &
\texttt{VipsInterpolate *} \\
\hline
\end{tabular}
\end{center}
\caption{Argument type macros\label{tab:type}}
\end{tab2}
The argument to the type macro is the name of the argument. These names
are used by user-interface programs to provide feedback, and sometimes as
variable names. The order in which you list the arguments is the order in
which user-interfaces will present them to the user. You should use the
following conventions when selecting names and an order for your arguments:
\begin{itemize}
\item
Names should be entirely in lower-case and contain no special characters,
apart from the digits 0-9 and the underscore character `\_'.
\item
Names should indicate the function of the argument. For example,
\verb+im_add()+ has the following argument names:
\begin{verbatim}
example% vips -help im_add
vips: args: in1 in2 out
where:
in1 is of type "image"
in2 is of type "image"
out is of type "image"
add two images, from package
"arithmetic"
flags:
(PIO function)
(no coordinate transformation)
(point-to-point operation)
\end{verbatim}
\item
You should order arguments with large input objects first, then output
objects, then any extra arguments or options. For example, \verb+im_extract()+
has the following sequence of arguments:
\begin{verbatim}
example% vips -help im_extract
vips: args: input output left top
width height channel
where:
input is of type "image"
output is of type "image"
left is of type "integer"
top is of type "integer"
width is of type "integer"
height is of type "integer"
channel is of type "integer"
extract area/band, from package
"conversion"
flags:
(PIO function)
(no coordinate transformation)
(point-to-point operation)
\end{verbatim}
\end{itemize}
This function sits over \verb+double_integer()+, providing VIPS with an
interface which it can call:
\begin{verbatim}
/* Call our function via a VIPS
* im_object vector.
*/
static int
double_vec( im_object *argv )
{
int *in = (int *) argv[0];
int *out = (int *) argv[1];
*out = double_integer( *in );
/* Always succeed.
*/
return( 0 );
}
\end{verbatim}
Finally, these two pieces of information (the argument description and
the VIPS-style function wrapper) can be gathered together into a function
description.
\begin{verbatim}
/* Description of double_integer.
*/
static im_function double_desc = {
"double_integer",
"double an integer",
0,
double_vec,
IM_NUMBER( arg_types ),
arg_types
};
\end{verbatim}
\label{sec:number}
\verb+IM_NUMBER()+ is a macro which returns the number of elements in a
static array. The \verb+flags+ field contains hints which user-interfaces
can use for various optimisations. At present, the possible values are:
\begin{description}
\item[\texttt{IM\_FN\_PIO}]
This function uses the VIPS PIO system (see \pref{sec:pio}).
\item[\texttt{IM\_FN\_TRANSFORM}]
This the function transforms coordinates.
\item[\texttt{IM\_FN\_PTOP}]
This is a point-to-point operation, that is, it can be replaced with a
look-up table.
\item[\texttt{IM\_FN\_NOCACHE}]
This operation has side effects and should not be cached. Useful for video
grabbers, for example.
\end{description}
This function description now needs to be added to the VIPS function database.
VIPS groups sets of related functions together in packages. There is only
a single function in this example, so we can just write:
\begin{verbatim}
/* Group up all the functions in this
* file.
*/
static im_function
*function_list[] = {
&double_desc
};
/* Define the package_table symbol.
* This is what VIPS looks for when
* loading the plugin.
*/
im_package package_table = {
"example",
IM_NUMBER( function_list ),
function_list
};
\end{verbatim}
The package has to be named \verb+package_table+, and has to be exported
from the file (that is, not a static). VIPS looks for a symbol of this name
when it opens your object file.
This file needs to be made into a dynamically loadable object. On my machine,
I can do this with:
\begin{verbatim}
example% gcc -fPIC -DPIC -c
`pkg-config vips-7.12 --cflags`
plug.c -o plug.o
example% gcc -shared plug.o
-o double.plg
\end{verbatim}
You can now use \verb+double.plg+ with any of the VIPS applications which
support function dispatch. For example:
\begin{verbatim}
example% vips -plugin double.plg \
double_integer 12
24
example%
\end{verbatim}
When VIPS starts up, it looks for a directory in the library directory called
\verb+vips-+, with the vips major and minor versions numbers as extensions,
and loads all files in there with the suffix \verb+.plg+. So for example, on
my machine, the plugin directory is \verb+/usr/lib/vips-7.16+ and any plugins
in that directory are automatically loaded into any VIPS programs on startup.
\subsection{A more complicated example}
This section lists the source for \verb+im_extract()+'s function
description. Almost all functions in the VIPS library have descriptors ---
if you are not sure how to write a description, it's usually easiest to
copy one from a similar function in the library.
\begin{verbatim}
/* Args to im_extract.
*/
static im_arg_desc
extract_args[] = {
IM_INPUT_IMAGE( "input" ),
IM_OUTPUT_IMAGE( "output" ),
IM_INPUT_INT( "left" ),
IM_INPUT_INT( "top" ),
IM_INPUT_INT( "width" ),
IM_INPUT_INT( "height" ),
IM_INPUT_INT( "channel" )
};
/* Call im_extract via arg vector.
*/
static int
extract_vec( im_object *argv )
{
IMAGE_BOX box;
box.xstart = *((int *) argv[2]);
box.ystart = *((int *) argv[3]);
box.xsize = *((int *) argv[4]);
box.ysize = *((int *) argv[5]);
box.chsel = *((int *) argv[6]);
return( im_extract(
argv[0], argv[1], &box ) );
}
/* Description of im_extract.
*/
static im_function
extract_desc = {
"im_extract",
"extract area/band",
IM_FN_PIO | IM_FN_TRANSFORM,
extract_vec,
NUMBER( extract_args ),
extract_args
};
\end{verbatim}
\subsection{Adding new types}
The VIPS type mechanism is extensible. User plug-ins can add new types
and user-interfaces can (to a certain extent) provide interfaces to these
user-defined types.
Here is the definition of \verb+im_arg_desc+:
\begin{verbatim}
/* Describe a VIPS command argument.
*/
typedef struct {
char *name;
im_type_desc *desc;
im_print_obj_fn print;
} im_arg_desc;
\end{verbatim}
The \verb+name+ field is the argument name above. The \verb+desc+ field
points to a structure defining the argument type, and the \verb+print+ field
is an (optionally \verb+NULL+) pointer to a function which VIPS will call
for output arguments after your function successfully completes and before
the object is destroyed. It can be used to print results to the terminal,
or to copy results into a user-interface layer.
\begin{verbatim}
/* Success on an argument. This is
* called if the image processing
* function succeeds and should be
* used to (for example) print
* output.
*/
typedef int (*im_print_obj_fn)
( im_object obj );
\end{verbatim}
\verb+im_type_desc+ is defined as:
\begin{verbatim}
/* Describe a VIPS type.
*/
typedef struct {
im_arg_type type;
int size;
im_type_flags flags;
im_init_obj_fn init;
im_dest_obj_fn dest;
} im_type_desc;
\end{verbatim}
Where \verb+im_arg_type+ is defined as
\begin{verbatim}
/* Type names. You may define your
* own, but if you use one of these,
* then you should use the built-in
* VIPS type converters.
*/
#define IM_TYPE_IMAGEVEC "imagevec"
#define IM_TYPE_DOUBLEVEC "doublevec"
#define IM_TYPE_INTVEC "intvec"
#define IM_TYPE_DOUBLE "double"
#define IM_TYPE_INT "integer"
#define IM_TYPE_COMPLEX "complex"
#define IM_TYPE_STRING "string"
#define IM_TYPE_IMASK "intmask"
#define IM_TYPE_DMASK "doublemask"
#define IM_TYPE_IMAGE "image"
#define IM_TYPE_DISPLAY "display"
#define IM_TYPE_GVALUE "gvalue"
typedef char *im_arg_type;
\end{verbatim}
In other words, it's just a string. When you add a new type, you just need
to choose a new unique string to name it. Be aware that the string is printed
to the user by various parts of VIPS, and so needs to be ``human-readable''.
The flags are:
\begin{verbatim}
/* These bits are ored together to
* make the flags in a type
* descriptor.
*
* IM_TYPE_OUTPUT: set to indicate
* output, otherwise input.
*
* IM_TYPE_ARG: Two ways of making
* an im_object --- with and without
* a command-line string to help you
* along. Arguments with a string
* are thing like IMAGE descriptors,
* which require a filename to
* initialise. Arguments without are
* things like output numbers, where
* making the object simply involves
* allocating storage.
*/
typedef enum {
IM_TYPE_OUTPUT = 0x1,
IM_TYPE_ARG = 0x2
} im_type_flags;
\end{verbatim}
And the \verb+init+ and \verb+destroy+ functions are:
\begin{verbatim}
/* Initialise and destroy objects.
* The "str" argument to the init
* function will not be supplied
* if this is not an ARG type.
*/
typedef int (*im_init_obj_fn)
( im_object *obj, char *str );
typedef int (*im_dest_obj_fn)
( im_object obj );
\end{verbatim}
As an example, here is the definition for a new type of unsigned
integers. First, we need to define the \verb+init+ and \verb+print+
functions. These transform objects of the type to and from string
representation.
\begin{verbatim}
/* Init function for unsigned int
* input.
*/
static int
uint_init( im_object *obj, char *str )
{
unsigned int *i = (int *) *obj;
if( sscanf( str, "%d", i ) != 1 ||
*i < 0 ) {
im_error( "uint_init",
"bad format" );
return( -1 );
}
return( 0 );
}
/* Print function for unsigned int
* output.
*/
static int
uint_print( im_object obj )
{
unsigned int *i =
(unsigned int *) obj;
printf( "%d\n", (int) *i );
return( 0 );
}
\end{verbatim}
Now we can define the type itself. We make two of these --- one for unsigned
int used as input, and one for output.
\begin{verbatim}
/* Name our type.
*/
#define TYPE_UINT "uint"
/* Input unsigned int type.
*/
static im_type_desc input_uint = {
TYPE_UINT, /* Its an int */
sizeof( unsigned int ),/* Memory */
IM_TYPE_ARG, /* Needs arg */
uint_init, /* Init */
NULL /* Destroy */
};
/* Output unsigned int type.
*/
static im_type_desc output_uint = {
TYPE_UINT, /* It's an int */
sizeof( unsigned int ),/* Memory */
IM_TYPE_OUTPUT, /* It's output */
NULL, /* Init */
NULL /* Destroy */
};
\end{verbatim}
Finally, we can define two macros to make structures of type
\verb+im_arg_desc+ for us.
\begin{verbatim}
#define INPUT_UINT( S ) \
{ S, &input_uint, NULL }
#define OUTPUT_UINT( S ) \
{ S, &output_uint, uint_print }
\end{verbatim}
For more examples, see the definitions for the built-in VIPS types.
\subsection{Using function dispatch in your application}
VIPS provides a set of functions for adding new image processing functions
to the VIPS function database, finding functions by name, and calling
functions. See the manual pages for full details.
\subsubsection{Adding and removing functions}
\begin{verbatim}
im_package *im_load_plugin(
const char *name );
\end{verbatim}
This function opens the named file, searches it for a symbol named
\verb+package_table+, and adds any functions it finds to the VIPS function
database. When you search for a function, any plug-ins are searched first,
so you can override standard VIPS function with your own code.
The function returns a pointer to the package it added, or \verb+NULL+
on error.
\begin{verbatim}
int im_close_plugins( void )
\end{verbatim}
This function closes all plug-ins, removing then from the VIPS function
database. It returns non-zero on error.
\subsubsection{Searching the function database}
\begin{verbatim}
void *im_map_packages(
im_list_map_fn fn, void *a )
\end{verbatim}
This function applies the argument function \verb+fn+ to every package
in the database, starting with the most recently added package. As with
\verb+im_list_map()+, the argument function should return \verb+NULL+
to continue searching, or non-\verb+NULL+ to terminate the search
early. \verb+im_map_packages()+ returns \verb+NULL+ if \verb+fn+ returned
\verb+NULL+ for all arguments. The extra argument \verb+a+ is carried around
by VIPS for your use.
For example, this fragment of code prints the names of all loaded packages
to \verb+fd+:
\begin{verbatim}
static void *
print_package_name( im_package *pack,
FILE *fp )
{
(void) fprintf( fp,
"package: \"%s\"\n",
pack->name );
/* Continue search.
*/
return( NULL );
}
static void
print_packages( FILE *fp )
{
(void) im_map_packages(
(im_list_map_fn)
print_package_name, fp );
}
\end{verbatim}
VIPS defines three convenience functions based on \verb+im_map_packages()+
which simplify searching for specific functions:
\begin{verbatim}
im_function *
im_find_function( char *name )
im_package *
im_find_package( char *name )
im_package *
im_package_of_function( char *name )
\end{verbatim}
\subsubsection{Building argument structures and running commands}
\begin{verbatim}
int im_free_vargv( im_function *fn,
im_object *vargv )
int im_allocate_vargv(
im_function *fn,
im_object *vargv )
\end{verbatim}
These two functions allocate space for and free VIPS argument lists. The
allocate function simply calls \verb+im_malloc()+ to allocate any store
that the types require (and also initializes it to zero). The free function
just calls \verb+im_free()+ for any storage that was allocated.
Note that neither of these functions calls the \verb+init+, \verb+dest+
or \verb+print+ functions for the types --- that's up to you.
\begin{verbatim}
int im_run_command( char *name,
int argc, char **argv )
\end{verbatim}
This function does everything. In effect,
\begin{verbatim}
im_run_command( "im_invert", 2,
{ "fred.v", "fred2.v", NULL } )
\end{verbatim}
is exactly equivalent to
\begin{verbatim}
system( "vips im_invert fred.v "
"fred2.v" )
\end{verbatim}
but no process is forked.

View File

@ -1,17 +0,0 @@
% configuration file for output of nipguide as html
\Preamble{html}
\begin{document}
% stop the mono font shrinkage we do for paper output
\renewenvironment{ctd}{\begin{quote}\tt}{\end{quote}}
% make a label
% in html, write an extra label which we can link to nip's help system
\renewcommand{\mylabel}[1]{
\label{#1}
\HCode{<a name="nip_label_#1"></a>}
}
% supress " on page xx" if we're making HTML
\renewcommand{\onpage}[1]{}
\EndPreamble

View File

@ -1,162 +0,0 @@
\section{Interpolators}
\label{sec:interpolate}
VIPS has a general system for representing pixel interpolators. You can select
an interpolator to pass to other VIPS operations, such as \verb+im_affinei()+,
you can add new interpolators, and you can write operations which take a
general interpolator as a parameter.
An interpolator is a function of the form:
\begin{verbatim}
typedef void (*VipsInterpolateMethod)( VipsInterpolate *,
PEL *out, REGION *in, double x, double y );
\end{verbatim}
\noindent
given the set of input pixels \verb+in+, it has to calculate a value for the
fractional position $(x, y)$ and write this value to the memory pointed to by
\verb+out+.
VIPS uses corner convention, so the value of pixel $(0, 0)$ is the value of
the surface the interpolator fits at the fractional position $(0.0, 0.0)$.
\subsection{How an interpolator is represented}
See the man page for \verb+VipsInterpolate+ for full details, but briefly,
an interpolator is a subclass of \verb+VipsInterpolate+ implementing the
following items:
\begin{itemize}
\item
An interpolation method, with the type signature above.
\item
A function \verb+get_window_size()+ which returns the size of the area of
pixels that the interpolator needs in order to calculate a value. For example,
a bilinear interpolator needs the four pixels surrounding the point to be
calculated, or a 2 by 2 window, so window size should be 2.
\item
Or if the window size is constant, you can leave \verb+get_window_size()+
NULL and just set the int value \verb+window_size+.
\end{itemize}
\subsection{A sample interpolator}
As an example, \fref{fg:newinterpolator} shows how to register a new
interpolator in a plugin.
\begin{fig2}
\begin{verbatim}
// This interpolator adds no new members.
typedef VipsInterpolate Myinterpolator;
typedef VipsInterpolateClass MyinterpolatorClass;
G_DEFINE_TYPE( Myinterpolator, myinterpolator, VIPS_TYPE_INTERPOLATE );
static void
myinterpolator_interpolate( VipsInterpolate *interpolate,
PEL *out, REGION *in, double x, double y )
{
MyinterpolatorClass *class =
MYINTERPOLATOR_GET_CLASS( interpolate );
/* Nearest-neighbor.
*/
memcpy( out,
IM_REGION_ADDR( in, floor( x ), floor( y ) ),
IM_IMAGE_SIZEOF_PEL( in->im ) );
}
static void
myinterpolator_class_init( MyinterpolatorClass *class )
{
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsInterpolateClass *interpolate_class = (VipsInterpolateClass *) class;
object_class->nickname = "myinterpolator";
object_class->description = _( "My interpolator" );
interpolate_class->interpolate = myinterpolator_interpolate;
}
static void
myinterpolate_init( Myinterpolate *object )
{
}
char *
g_module_check_init( GModule *self )
{
// register the type
myinterpolator_get_type();
}
\end{verbatim}
\caption{Registering an interpolator in a plugin}
\label{fg:newinterpolator}
\end{fig2}
\subsection{Writing a VIPS operation that takes an interpolator as an argument}
Operations just take a \verb+VipsInterpolate+ as an argument, for example:
\begin{verbatim}
int im_affinei_all( IMAGE *in, IMAGE *out,
VipsInterpolate *interpolate,
double a, double b, double c, double d,
double dx, double dy );
\end{verbatim}
To use the interpolator, use \verb+vips_interpolate()+:
\begin{verbatim}
void vips_interpolate( VipsInterpolate *interpolate,
PEL *out, REGION *in, double x, double y );
\end{verbatim}
\noindent
This looks up the interpolate method for the object and calls it for you.
You can save the cost of the lookup in an inner loop with
\verb+vips_interpolate_get_method()+:
\begin{verbatim}
VipsInterpolateMethod
vips_interpolate_get_method(
VipsInterpolate *interpolate );
\end{verbatim}
\subsection{Passing an interpolator to a VIPS operation}
You can build an instance of a \verb+VipsInterpolator+ with
the \verb+vips_object_*()+ family of functions, see \pref{sec:object}.
Convenience functions return a static instance of one of the standard
interpolators:
\begin{verbatim}
VipsInterpolate *vips_interpolate_nearest_static( void );
VipsInterpolate *vips_interpolate_bilinear_static( void );
\end{verbatim}
\noindent
Don't free the result.
Finally, \verb+vips_interpolate_new()+ makes a \verb+VipsInterpolate+ from a
nickname:
\begin{verbatim}
VipsInterpolate *vips_interpolate_new( const char *nickname );
\end{verbatim}
For example:
\begin{verbatim}
VipsInterpolate *interpolate = vips_interpolate_new( "nohalo" );
\end{verbatim}
\noindent
You must drop your ref after you're done with the object with
\verb+g_object_unref()+.

View File

@ -1,836 +0,0 @@
\section{Core C API}
VIPS is built on top of several other libraries, two of which, glib and
gobject, are exposed at various points in the C API.
You can read up on glib at the GTK+ website:
\begin{verbatim}
http://www.gtk.org
\end{verbatim}
There's also an excellent book by Matthias Warkus, \emph{The Official
GNOME 2 Developer's Guide}, which covers the same material in a tutorial
manner.
\subsection{Startup}
Before calling any VIPS function, you need to start VIPS up:
\begin{verbatim}
int im_init_world( const char *argv0 );
\end{verbatim}
The \verb+argv0+ argument is the value of \verb+argv[0]+ your
program was passed by the host operating system. VIPS uses this with
\verb+im_guess_prefix()+ and \verb+im_guess_libdir()+ to try to find various
VIPS data files.
If you don't call this function, VIPS will call it for you the first time you
use a VIPS function. But it won't be able to get the \verb+argv0+ value for
you, so it may not be able to find it's data files.
VIPS also offers the optional:
\begin{verbatim}
GOptionGroup *im_get_option_group( void );
\end{verbatim}
You can use this with GOption to parse your program's command-line arguments.
It adds several useful VIPS flags, including \verb+--vips-concurrency+.
\fref{fg:hello} shows both these functions in use. Again, the GOption stuff is
optional and just lets VIPS add some flags to your program. You do need the
\verb+im_init_world()+ though.
\begin{fig2}
\begin{verbatim}
#include <stdio.h>
#include <vips/vips.h>
static gboolean print_stuff;
static GOptionEntry options[] = {
{ "print", 'p', 0, G_OPTION_ARG_NONE, &print_stuff,
"print \"hello world!\"", NULL },
{ NULL }
};
int
main( int argc, char **argv )
{
GOptionContext *context;
GError *error = NULL;
if( im_init_world( argv[0] ) )
error_exit( "unable to start VIPS" );
context = g_option_context_new( "- my program" );
g_option_context_add_main_entries( context,
options, "main" );
g_option_context_add_group( context, im_get_option_group() );
if( !g_option_context_parse( context, &argc, &argv, &error ) ) {
if( error ) {
fprintf( stderr, "%s\n", error->message );
g_error_free( error );
}
error_exit( "try \"%s --help\"", g_get_prgname() );
}
g_option_context_free( context );
if( print_stuff )
printf( "hello, world!\n" );
return( 0 );
}
\end{verbatim}
\caption{Hello World for VIPS}
\label{fg:hello}
\end{fig2}
\subsection{Image descriptors}
The base level of the VIPS I/O system provides \verb+IMAGE+ descriptors.
An image represented by a descriptor may be an image file on disc, an area
of memory that has been allocated for the image, an output file, a delayed
computation, and so on. Programs need (usually) only know that they have
a descriptor, they do not see many of the details. \fref{fg:image}
shows the definition of the \verb+IMAGE+ descriptor.
\begin{fig2}
\begin{verbatim}
typedef struct {
/* Fields from image header.
*/
int Xsize; /* Pels per line */
int Ysize; /* Lines */
int Bands; /* Number of bands */
int Bbits; /* Bits per band */
int BandFmt; /* Band format */
int Coding; /* Coding type */
int Type; /* Type of file */
float XRes; /* Horizontal res in pels/mm */
float YRes; /* Vertical res in pels/mm */
int Length; /* Obsolete (unused) */
short Compression; /* Obsolete (unused) */
short Level; /* Obsolete (unused) */
int Xoffset; /* Position of origin */
int Yoffset;
/* Derived fields that may be read by the user.
*/
char *filename; /* File name */
im_time_t *time; /* Timing for eval callback */
int kill; /* Set to non-zero to block eval */
... and lots of other private fields used by VIPS for
... housekeeping.
} IMAGE;
\end{verbatim}
\caption{The \texttt{IMAGE} descriptor}
\label{fg:image}
\end{fig2}
The first set of fields simply come from the image file header:
see \pref{sec:header} for a full description of all the fields. The next
set are maintained for you by the VIPS I/O system. \verb+filename+ is the
name of the file that this image came from. If you have attached an eval
callback to this image, \verb+time+ points to a set of timing statistics
which can be used by user-interfaces built on VIPS to provide feedback
about the progress of evaluation --- see \pref{sec:eval}. Finally, if you
set \verb+kill+ to non-zero, VIPS will block any pipelines which use this
descriptor as an intermediate. See \pref{sec:block}.
The remaining fields are private and are used by VIPS for housekeeping.
\subsection{Header fields}
\label{sec:fields}
You can access header fields either directly (as \verb+im->Xsize+, for
example) or programmatically with \verb+im_header_int()+ and friends. For
example:
\begin{verbatim}
int i;
im_header_int( im, "Xsize", &i );
\end{verbatim}
There's also \verb+im_header_map()+ to loop over header fields, and
\verb+im_header_get_type+ to test the type of fields. These functions work for
image meta fields as well, see \pref{sec:meta}.
\subsection{Opening and closing}
\label{sec:open}
Descriptors are created with \verb+im_open()+. You can also read images with
the format system: see \pref{sec:format}. The two APIs are complimentary,
though \verb+im_open()+ is more useful.
At the command-line, try:
\begin{verbatim}
$ vips list classes
\end{verbatim}
/noindent
to see a list of all the supported file formats.
\verb+im_open()+ takes a file name and a string representing the mode with
which the descriptor is to be opened:
\begin{verbatim}
IMAGE *im_open( const char *filename,
const char *mode )
\end{verbatim}
The possible values for mode are:
\begin{description}
\item[\texttt{"r"}]
The file is opened read-only.
If you open a non-VIPS image, or a VIPS image written on a machine with a
different byte ordering, \verb+im_open()+ will automatically convert it to
native VIPS format. If the underlying file does not support random access
(JPEG, for example), the entire file will be converted in memory.
VIPS can read images in many file formats. You can control the details of
the conversion with extra characters embedded in the filename. For example:
\begin{verbatim}
fred = im_open( "fred.tif:2",
"r" );
\end{verbatim}
\noindent
will read page 2 of a multi-page TIFF. See the man pages for details.
\item[\texttt{"w"}]
An \verb+IMAGE+ descriptor is created which, when written to, will write
pixels to disc in the specified file. Any existing file of that name is
deleted.
VIPS looks at the filename suffix to determine the save format. If there
is no suffix, or the filename ends in \verb+".v"+, the image is written
in VIPS native format.
If you want to control the details of the conversion to the disc format (such
as setting the Q factor for a JPEG, for example), you embed extra control
characters in the filename. For example:
\begin{verbatim}
fred = im_open( "fred.jpg:95",
"w" );
\end{verbatim}
\noindent
writes to \verb+fred+ will write a JPEG with Q 95. Again, see the man pages
for the conversion functions for details.
\item[\texttt{"t"}]
As the \verb+"w"+ mode, but pels written to the descriptor will be saved
in a temporary memory buffer.
\item[\texttt{"p"}]
This creates a special partial image. Partial images are used to join VIPS
operations together, see \pref{sec:joinup}.
\item[\texttt{"rw"}]
As the \verb+"r"+ mode, but the image is mapped into the caller's address
space read-write. This mode is only provided for the use of paintbox-style
applications which need to directly modify an image. Most programs should
use the \verb+"w"+ mode for image output.
\end{description}
If an error occurs opening the image, \verb+im_open()+ calls
\verb+im_error()+ with a string describing the cause of the error and
returns \verb+NULL+. \verb+im_error()+ has type
\begin{verbatim}
void im_error( const char *domain,
const char *format, ... )
\end{verbatim}
\noindent
The first argument is a string giving the name of the thing that raised
the error (just \verb+"im_open"+, for example). The format and subsequent
arguments work exactly as \verb+printf()+. It formats the message and
appends the string formed to the error log. You can get a pointer to the
error text with \verb+im_error_buffer()+.
\begin{verbatim}
const char *im_error_buffer()
\end{verbatim}
\noindent
Applications may display this string to give users feedback about the
cause of the error. The VIPS exit function, \verb+error_exit()+, prints
\verb+im_error_buffer()+ to \verb+stderr+ and terminates the program with an
error code of 1.
\begin{verbatim}
void error_exit( const char *format,
... )
\end{verbatim}
\noindent
There are other functions for handling errors: see the man page for
\verb+im_error()+.
Descriptors are closed with \verb+im_close()+. It has type:
\begin{verbatim}
int im_close( IMAGE *im )
\end{verbatim}
\verb+im_close()+ returns 0 on success and non-zero on error.
\subsection{Examples}
\label{sec:examples}
As an example, \fref{fg:widthheight} will print the width and height
of an image stored on disc.
\begin{fig2}
\begin{verbatim}
#include <stdio.h>
#include <vips/vips.h>
int
main( int argc, char **argv )
{
IMAGE *im;
/* Check arguments.
*/
if( im_init_world( argv[0] ) )
error_exit( "unable to start VIPS" );
if( argc != 2 )
error_exit( "usage: %s filename", argv[0] );
/* Open file.
*/
if( !(im = im_open( argv[1], "r" )) )
error_exit( "unable to open %s for input", argv[1] );
/* Process.
*/
printf( "width = %d, height = %d\n", im->Xsize, im->Ysize );
/* Close.
*/
if( im_close( im ) )
error_exit( "unable to close %s", argv[1] );
return( 0 );
}
\end{verbatim}
\label{fg:widthheight}
\caption{Print width and height of an image}
\end{fig2}
To compile this example, use:
\begin{verbatim}
cc `pkg-config vips-7.14 \
--cflags --libs` myfunc.c
\end{verbatim}
As a slightly more complicated example, \fref{fg:negative}
will calculate the photographic negative of an image.
\begin{fig2}
\begin{verbatim}
#include <stdio.h>
#include <vips/vips.h>
int
main( int argc, char **argv )
{
IMAGE *in, *out;
/* Check arguments.
*/
if( im_init_world( argv[0] ) )
error_exit( "unable to start VIPS" );
if( argc != 3 )
error_exit( "usage: %s infile outfile", argv[0] );
/* Open images for read and write, invert, update the history with our
* args, and close.
*/
if( !(in = im_open( argv[1], "r" )) ||
!(out = im_open( argv[2], "w" )) ||
im_invert( in, out ) ||
im_updatehist( out, argc, argv ) ||
im_close( in ) ||
im_close( out ) )
error_exit( argv[0] );
return( 0 );
}
\end{verbatim}
\label{fg:negative}
\caption{Find photographic negative}
\end{fig2}
\subsection{Metadata}
\label{sec:meta}
VIPS lets you attach arbitrary metadata to an IMAGE. For example, ICC
profiles, EXIF tags, image history, whatever you like. VIPS will efficiently
propagate metadata as images are processed (usually just by copying
pointers) and will automatically save and load metadata from VIPS files
(see \pref{sec:header}).
A piece of metadata is a value and an identifying name. A set of
convenience functions let you set and get int, double, string and blob. For
example:
\begin{verbatim}
int im_meta_set_int( IMAGE *,
const char *field, int );
int im_meta_get_int( IMAGE *,
const char *field, int * );
\end{verbatim}
So you can do:
\begin{verbatim}
if( im_meta_set_int( im, "poop", 42 ) )
return( -1 );
\end{verbatim}
\noindent
to create an int called \verb+"poop"+, then at some later point (possibly much,
much later), in an image distantly derived from \verb+im+, you can use:
\begin{verbatim}
int i;
if( im_meta_get_int( im, "poop", &i ) )
return( -1 );
\end{verbatim}
\noindent
And get the value 42 back.
You can use \verb+im_meta_set()+ and \verb+im_meta_get()+ to attach arbitrary
\verb+GValue+ to images. See the man page for \verb+im_meta_set()+ for
full details.
You can test for a field being present with \verb+im_meta_get_type()+ (you'll
get \verb+G_TYPE_INT+ back for \verb+"poop"+, for example, or 0 if it is not
defined for this image).
\subsection{History}
\label{sec:history}
VIPS tracks the history of an image, that is, the sequence of operations which
have led to the creation of an image. You can view a VIPS image's history with
the \verb+header+ command, or with \nip{}'s \ct{View Header} menu. Whenever an
application performs an action, it should append a line of shell script to the
history which would perform the same action.
The call to \verb+im_updatehist()+ in \fref{fg:negative} adds a line to the
image history noting the invocation of this program, its arguments, and the
time and date at which it was run. You may also find \verb+im_histlin()+
helpful. It has type:
\begin{verbatim}
void im_histlin( IMAGE *im,
const char *fmt, ... )
\end{verbatim}
\noindent
It formats its arguments as \verb+printf()+ and appends the string formed
to the image history.
You read an image's history with \verb+im_history_get()+. It returns the
entire history of an image, one action per line. No need to free the result.
\begin{verbatim}
const char *
im_history_get( IMAGE *im );
\end{verbatim}
\subsection{Eval callbacks}
\label{sec:eval}
VIPS lets you attach callbacks to image descriptors. These are functions
you provide which VIPS will call when certain events occur. See
\pref{sec:callback} for more detail.
Eval callbacks are called repeatedly during evaluation and can be used by
user-interface programs to give feedback about the progress of evaluation.
\subsection{Detailed rules for descriptors}
These rules are intended to answer awkward questions.
\begin{enumerate}
\item
You can output to a descriptor only once.
\item
You can use a descriptor as an input many times.
\item
You can only output to a descriptor that was opened with modes \verb+"w"+,
\verb+"t"+ and \verb+"p"+.
\item
You can only use a descriptor as input if it was opened with modes \verb+"r"+
or \verb+"rw"+.
\item
If you have output to a descriptor, you may subsequently use it as an
input. \verb+"w"+ descriptors are automatically changed to \verb+"r"+
descriptors.
If the function you are passing the descriptor to uses WIO (see
\pref{sec:limit}), then \verb+"p"+ descriptors become \verb+"t"+.
If the function you are passing the descriptor to uses PIO, then \verb+"p"+
descriptors are unchanged.
\end{enumerate}
\subsection{Automatic resource deallocation}
VIPS lets you allocate resources local to an image descriptor, that is,
when the descriptor is closed, all resources which were allocated local to
that descriptor are automatically released for you.
\subsubsection{Local image descriptors}
VIPS provides a function which will open a new image local to
an existing image. \verb+im_open_local()+ has type:
\begin{verbatim}
IMAGE *im_open_local( IMAGE *im,
const char *filename,
const char *mode )
\end{verbatim}
It behaves exactly as \verb+im_open()+, except that you do not need to close
the descriptor it returns. It will be closed automatically when its parent
descriptor \verb+im+ is closed.
\begin{fig2}
\begin{verbatim}
/* Add another image to the accumulated total.
*/
static int
sum1( IMAGE *acc, IMAGE **in, int nin, IMAGE *out )
{
IMAGE *t;
if( nin == 0 )
/* All done ... copy to out.
*/
return( im_copy( acc, out ) );
/* Make a new intermediate, and add to it..
*/
return( !(t = im_open_local( out, "sum1:1", "p" )) ||
im_add( acc, in[0], t ) ||
sum1( t, in + 1, nin - 1, out ) );
}
/* Sum the array of images in[]. nin is the number of images in
* in[], out is the descriptor we write the final image to.
*/
int
total( IMAGE **in, int nin, IMAGE *out )
{
/* Check that we have at least one image.
*/
if( nin <= 0 ) {
im_error( "total", "nin should be > 0" );
return( -1 );
}
/* More than 1, sum recursively.
*/
return( sum1( in[0], in + 1, nin - 1, out ) );
}
\end{verbatim}
\caption{Sum an array of images}
\label{fg:addemup}
\end{fig2}
\fref{fg:addemup} is a function which will sum an array of images.
We need never close any of the (unknown) number of intermediate images which
we open. They will all be closed for us by our caller, when our caller
finally closes \verb+out+. VIPS lets local images themselves have local
images and automatically makes sure that all are closed in the correct order.
It is very important that these intermediate images are made local to
\verb+out+ rather than \verb+in+, for reasons which should become apparent
in the section on combining operations below.
There's also \verb+im_open_local_array()+ for when you need a lot of local
descriptors, see the man page.
\subsubsection{Local memory allocation}
\label{sec:malloc}
VIPS includes a set of functions for memory allocation local to an image
descriptor. The base memory allocation function is \verb+im_malloc()+. It
has type:
\begin{verbatim}
void *im_malloc( IMAGE *, size_t )
\end{verbatim}
It operates exactly as the standard \verb+malloc()+ C library function,
except that the area of memory it allocates is local to an image.
If \verb+im_malloc()+ is unable to allocate memory, it returns
\verb+NULL+. If you pass \verb+NULL+ instead of a valid image descriptor,
then \verb+im_malloc()+ allocates memory globally and you must free it
yourself at some stage.
To free memory explicitly, use \verb+im_free()+:
\begin{verbatim}
int im_free( void * )
\end{verbatim}
\noindent
\verb+im_free()+ always returns 0, so you can use it as an argument to a
callback.
Three macros make memory allocation even easier. \verb+IM_NEW()+ allocates
a new object. You give it a descriptor and a type, and it returns a pointer
to enough space to hold an object of that type. It has type:
\begin{verbatim}
type-name *IM_NEW( IMAGE *, type-name )
\end{verbatim}
The second macro, \verb+IM_ARRAY()+, is very similar, but allocates
space for an array of objects. Note that, unlike the usual \verb+calloc()+
C library function, it does not initialise the array to zero. It has type:
\begin{verbatim}
type-name *IM_ARRAY( IMAGE *, int, type-name )
\end{verbatim}
Finally, \verb+IM_NUMBER()+ returns the number of elements in an array of
defined size. See the man pages for a series of examples, or
see \pref{sec:number}.
\subsubsection{Other local operations}
The above facilities are implemented with the VIPS core function
\verb+im_add_close_callback()+. You can use this facility to make your own
local resource allocators for other types of object --- see the manual page
for more help.
\subsection{Error handling}
All VIPS operations return 0 on success and non-zero on error, setting
\verb+im_error()+. As a consequence, when a VIPS function fails, you do not
need to generate an error message --- you can simply propagate the error back
up to your caller. If however you detect some error yourself (for example,
the bad parameter in the example above), you must call \verb+im_error()+
to let your caller know what the problem was.
VIPS provides two more functions for error message handling: \verb+im_warn()+
and \verb+im_diag()+. These are intended to be used for less serious
messages, as their names suggest. Currently, they simply format and print
their arguments to \verb+stderr+, optionally suppressed by the setting of an
environment variable. Future releases of VIPS may allow more sophisticated
trapping of these functions to allow their text to be easily presented to
the user by VIPS applications. See the manual pages.
\subsection{Joining operations together}
\label{sec:joinup}
VIPS lets you join image processing operations together so that they
behave as a single unit. \fref{fg:join} shows the definition of the
function \verb+im_Lab2disp()+ from the VIPS library. This function converts
an image in \cielab{} colour space to an RGB image for a monitor. The
monitor characteristics (gamma, phosphor type, etc.) are described by the
\verb+im_col_display+ structure, see the man page for \verb+im_col_XYZ2rgb()+.
\begin{fig2}
\begin{verbatim}
int
im_Lab2disp( IMAGE *in, IMAGE *out, struct im_col_display *disp )
{
IMAGE *t1;
if( !(t1 = im_open_local( out, "im_Lab2disp:1", "p" )) ||
im_Lab2XYZ( in, t1 ) ||
im_XYZ2disp( t1, out, disp ) )
return( -1 );
return( 0 );
}
\end{verbatim}
\caption{Two image-processing operations joined together}
\label{fg:join}
\end{fig2}
The special \verb+"p"+ mode (for partial) used to open the image descriptor
used as the intermediate image in this function `glues' the two operations
together. When you use \verb+im_Lab2disp()+, the two operations inside it
will execute together and no extra storage is necessary for the intermediate
image (\verb+t1+ in this example). This is important if you want to process
images larger than the amount of RAM you have on your machine.
As an added bonus, if you have more than one CPU in your computer, the work
will be automatically spread across the processors for you. You can control
this parallelization with the \verb+IM_CONCURRENCY+ environment variable,
\verb+im_concurrency_set()+, and with the \verb+--vips-concurrency+
command-line switch. See the man page for \verb+im_generate()+.
\subsubsection{How it works}
When a VIPS function is asked to output to a \verb+"p"+ image descriptor,
all the fields in the descriptor are set (the output image size and type
are set, for example), but no image data is actually generated. Instead,
the function attaches callbacks to the image descriptor which VIPS can use
later to generate any piece of the output image that might be needed.
When a VIPS function is asked to output to a \verb+"w"+ or a \verb+"t"+
descriptor (a real disc file or a real memory buffer), it evaluates
immediately and its evaluation in turn forces the evaluation of any earlier
\verb+"p"+ images.
In the example in \fref{fg:join}, whether or not any pixels are really
processed when \verb+im_Lab2disp()+ is called depends upon the mode in
which \verb+out+ was opened. If \verb+out+ is also a partial image, then
no pixels will be calculated --- instead, a pipeline of VIPS operations
will be constructed behind the scenes and attached to \verb+out+.
Conversely, if \verb+out+ is a real image (that is, either \verb+"w"+
or \verb+"t"+), then the final VIPS operation in the function
(\verb+im_XYZ2disp()+) will output the entire image to \verb+out+, causing
the earlier parts of \verb+im_Lab2disp()+ (and indeed possibly some earlier
pieces of program, if \verb+in+ was also a \verb+"p"+ image) to run.
When a VIPS pipeline does finally evaluate, all of the functions in the
pipeline execute together, sucking image data through the system in small
pieces. As a consequence, no intermediate images are generated, large
amounts of RAM are not needed, and no slow disc I/O needs to be performed.
Since VIPS partial I/O is demand-driven rather than data-driven this works
even if some of the operations perform coordinate transformations. We could,
for example, include a call to \verb+im_affine()+, which performs
arbitrary rotation and scaling, and everything would still work correctly.
\subsubsection{Pitfalls with partials}
To go with all of the benefits that partial image I/O brings, there are
also some problems. The most serious is that you are often not quite certain
when computation will happen. This can cause problems if you close an input
file, thinking that it is finished with, when in fact that file has not
been processed yet. Doing this results in dangling pointers and an almost
certain core-dump.
You can prevent this from happening with careful use of
\verb+im_open_local()+. If you always open local to your output image,
you can be sure that the input will not be closed before the output has been
generated to a file or memory buffer. You do not need to be so careful with
non-image arguments. VIPS functions which take extra non-image arguments
(a matrix, perhaps) are careful to make their own copy of the object before
returning.
\subsubsection{Non-image output}
Some VIPS functions consume images, but make no image
output. \verb+im_stats()+ for example, scans an image calculating various
statistical values. When you use \verb+im_stats()+, it behaves as a data
sink, sucking image data through any earlier pipeline stages.
\subsubsection{Calculating twice}
In some circumstances, the same image data can be generated twice.
\fref{fg:thrmean} is a function which finds the mean value of an
image, and writes a new image in which pixels less than the mean are set to
0 and images greater than the mean are set to 255.
\begin{fig2}
\begin{verbatim}
int
threshold_at_mean( IMAGE *in, IMAGE *out )
{
double mean;
if( im_avg( in, &mean ) ||
im_moreconst( in, out, mean ) )
return( -1 );
return( 0 );
}
\end{verbatim}
\caption{Threshold an image at the mean value}
\label{fg:thrmean}
\end{fig2}
This seems straightforward --- but consider if image \verb+in+ were a
\verb+"p"+, and represented the output of a large pipeline of operations. The
call to \verb+im_avg()+ would force the evaluation of the entire pipeline,
and throw it all away, keeping only the average value. The subsequent call to
\verb+im_moreconst()+ will cause the pipeline to be evaluated a second time.
When designing a program, it is sensible to pay attention to these
issues. It might be faster, in some cases, to output to a file before
calling \verb+im_avg()+, find the average of the disc file, and then run
\verb+im_moreconst()+ from that. There's also \verb+im_cache()+ which can keep
recent parts of a very large image.
\subsubsection{Blocking computation}
\label{sec:block}
\verb+IMAGE+ descriptors have a flag called \verb+kill+ which can be used
to block computation. If \verb+im->kill+ is set to a non-zero value,
then any VIPS pipelines which use \verb+im+ as an intermediate will fail
with an error message. This is useful for user-interface writers ---
suppose your interface is forced to close an image which many other images
are using as a source of data. You can just set the \verb+kill+ flag in all
of the deleted image's immediate children and prevent any dangling pointers
from being followed.
\subsubsection{Limitations}
\label{sec:limit}
Not all VIPS operations are partial-aware. These non-partial operations
use a pre-VIPS 7.0 I/O scheme in which the whole of the input image has to
be present at the same time. In some cases, this is because partial I/O
simply makes no sense --- for example, a Fourier Transform can produce no
output until it has seen all of the input. \verb+im_fwfft()+ is therefore
not a partial operation. In other cases, we have simply not got around to
rewriting the old non-partial operation in the newer partial style.
You can mix partial and non-partial VIPS operations freely, without worrying
about which type they are. The only effect will be on the time your pipeline
takes to execute, and the memory requirements of the intermediate images. VIPS
uses the following rules when you mix the two styles of operation:
\begin{enumerate}
\item
When a non-partial operation is asked to output to a partial image descriptor,
the \verb+"p"+ descriptor is magically transformed into a \verb+"t"+
descriptor.
\item
When a non-partial operation is asked to read from a \verb+"p"+ descriptor,
the \verb+"p"+ descriptor is turned into a \verb+"t"+ type, and any earlier
stages in the pipeline forced to evaluate into that memory buffer.
The non-partial operation then processes from the memory buffer.
\end{enumerate}
These rules have the consequence that you may only process very large images
if you only use partial operations. If you use any non-partial operations,
then parts of your pipelines will fall back to old whole-image I/O and you
will need to think carefully about where your intermediates should be stored.

View File

@ -1,56 +0,0 @@
\section{Programming in-place functions}
VIPS includes a little support for in-place functions --- functions
which operate directly on an image, both reading and writing from the same
descriptor via the data pointer. This is an extremely dangerous way to
handle IO, since any bugs in your program will trash your input image.
Operations of this type should call \verb+im_rwcheck()+ instead of
\verb+im_incheck()+. \verb+im_rwcheck()+ tries to get a descriptor ready
for in-place writing. For example, a function which cleared an image to
black might be written as:
\begin{verbatim}
#include <stdio.h>
#include <memory.h>
#include <vips/vips.h>
int
black_inplace( IMAGE *im )
{
/* Check that we can RW to im.
*/
if( im_rwcheck( im ) )
return( -1 );
/* Zap the image!
*/
memset( im->data, 0,
IM_IMAGE_SIZEOF_LINE( im ) *
im->Ysize );
return( 0 );
}
\end{verbatim}
This function might be called from an application as:
\begin{verbatim}
#include <stdio.h>
#include <stdlib.h>
#include <vips/vips.h>
void
zap( char *name )
{
IMAGE *im;
if( !(im = im_open( name, "rw" )) ||
black_inplace( im ) ||
im_updatehist( im, "zap image" ) ||
im_close( im ) )
error_exit( "failure!" );
}
\end{verbatim}

View File

@ -1,113 +0,0 @@
% My defs
% Computer Text, Computer text=>, Computer Text Display
\newcommand{\ct}[1]{\texttt{#1}}
\newcommand{\ctr}[1]{\ct{#1} / }
\newenvironment{ctd}{\begin{quote}\footnotesize\tt}{\end{quote}}
\pagecolor{white}
% abbreviations
\newcommand{\vips}{\ct{vips}}
\newcommand{\nip}{\ct{nip2}}
\newcommand{\bs}{$\backslash$}
\newcommand{\rtp}{\^{ }}
\newcommand{\cielab}{\emph{CIE~}$L^{*}a^{*}b^{*}$}
\newcommand{\ciexyz}{\emph{CIE XYZ}}
\newcommand{\cieyxy}{\emph{CIE Yxy}}
\newcommand{\cielch}{\emph{CIE LCh}}
\newcommand{\cieucs}{\emph{UCS(1:1)}}
\newcommand{\cross}{$\times{}$}
% make a label ... override this for HTML output
\newcommand{\mylabel}[1]{\label{#1}}
% generate " on page xx" if a label is referring to something on another page
% override this for HTML output
\newcounter{boink}
\newcommand{\onpage}[1]{%
\addtocounter{boink}{1}%
\label{atref\theboink{}}%
\ifthenelse{\pageref{atref\theboink{}}=\pageref{#1}}%
{}%
{ on page~\pageref{#1}}}
% format a reference to a section .. "$3.11 on page 37"
\newcommand{\pref}[1]{\S\ref{#1}\onpage{#1}}
\newcommand{\tref}[1]{Table~\ref{#1}\onpage{#1}}
\newcommand{\fref}[1]{Figure~\ref{#1}\onpage{#1}}
\newcommand{\cref}[1]{Chapter~\ref{#1}\onpage{#1}}
\newcommand{\aref}[1]{Appendix~\ref{#1}\onpage{#1}}
% Insert a file ... height and name.
\newcommand{\fig}[2]{
\begin{center}
\includegraphics[height=#1]{figs/#2}
\end{center}
}
% Insert a file ... width and name.
\newcommand{\figw}[2]{
\begin{center}
\includegraphics[width=#1]{figs/#2}
\end{center}
}
% make a 2-column figure ... define our own so we can easily override in html
% output
\newenvironment{fig2}{\begin{figure*}}{\end{figure*}}
% same for 2-col tables
\newenvironment{tab2}{\begin{table*}}{\end{table*}}
% environment for setting ip defs
\newenvironment{ipdef}{
\par
\samepage
\begin{ctd}
\begin{tabular}{@{\hspace{0.2em}}ll@{\hspace{0.2em}}ll@{\hspace{0.2em}}ll@{\hspace{0.2em}}ll@{\hspace{0.2em}}ll@{\hspace{0.2em}}ll@{\hspace{0.2em}}ll@{\hspace{0.2em}}lllllllllllllllllllllllllllll}
~~~ & ~ & ~~~ & ~ & ~~~ & ~ & ~~~ & ~ & ~~~ & ~ & ~~~ & ~ & ~~~ & ~ & ~~~ & \\[-1.3em]
}{
\end{tabular}
\end{ctd}
\par
}
% causes problems for htlatex :-(
% make this a noop for now
% \newcommand{\dtxt}[1]{\multicolumn{25}{@{\hspace{0.2em}}l}{#1}}
\newcommand{\dtxt}[1]{#1}
% Insert a blank page
\newcommand{\blankpage}{%
\newpage
~~~~
\pagestyle{plain}
\newpage
% Another one necessary in twocolumn mode
~~~~
\newpage
\pagestyle{fancy}
}
%\addtolength{\headheight}{3pt}
% Make text a bit wider, since we are two column.
\addtolength{\textwidth}{0.5in}
\addtolength{\oddsidemargin}{-0.25in}
\addtolength{\evensidemargin}{-0.25in}
% twocolumn seems to remove the binding offset ... add it back
%\addtolength{\oddsidemargin}{-0.2in}
%\addtolength{\evensidemargin}{0.2in}
% More space between headers and footers and the body
\addtolength{\topmargin}{-0.5em}
\addtolength{\headsep}{0.5em}
\addtolength{\footskip}{0.5em}
% Swap left and right binding offsets
\newlength{\fred}
\setlength{\fred}{\oddsidemargin}
\setlength{\oddsidemargin}{\evensidemargin}
\setlength{\evensidemargin}{\fred}

View File

@ -1,134 +0,0 @@
\section{The VIPS base class: \texttt{VipsObject}}
\label{sec:object}
VIPS is in the process of moving to an object system based on \verb+GObject+.
You can read about the \verb+GObjec+ library at the GTK+ website:
\begin{verbatim}
http://www.gtk.org
\end{verbatim}
We've implemented two new subsystems (\verb+VipsFormat+ and
\verb+VipsInterpolate+) on top of \verb+VipsObject+ but not yet moved the core
VIPS types over. As a result, \verb+VipsObject+ is still developing and is
likely to change in the next release.
This section quickly summarises enough of the \verb+VipsObject+ system to let
you use the two derived APIs but that's all. Full documentation will come when
this system stabilises.
\subsection{Properties}
Like the rest of VIPS, \verb+VipsObject+ is a functional type. You can set
properties during object construction, but not after that point. You may read
properties at any time after construction, but not before.
To enforce these rules, VIPS extends the standard \verb+GObject+ property
system and adds a new phase to object creation. An object has the following
stages in its life:
\subsubsection{Lookup}
\verb+vips_type_find()+ is a convenience function that looks up a type by its
nickname relative to a base class. For example:
\begin{verbatim}
GType type =
vips_type_find( "VipsInterpolate", "bilinear" );
\end{verbatim}
\noindent
finds a subclass of \verb+VipsInterpolate+ nicknamed `bilinear'. You can look
up types by their full name of course, but these can be rather unwieldy
(\verb+VipsInterpolateBilinear+ in this case, for example).
\subsubsection{Create}
Build an instance with \verb+g_object_new()+. For example:
\begin{verbatim}
VipsObject *object =
g_object_new( type,
"sharpness", 12.0,
NULL );
\end{verbatim}
You can set any of the object's properties in the constructor. You can
continue to set, but not read, any other properties, for example:
\begin{verbatim}
g_object_set( object,
"sharpness", 12.0,
NULL );
\end{verbatim}
You can loop over an object's required and optional parameters with
\verb+vips_argument_map()+.
\subsubsection{Build}
Once all of the required any any of the optional object parameters have been
set, call \verb+vips_object_build()+:
\begin{verbatim}
int vips_object_build( VipsObject *object );
\end{verbatim}
This function checks that all the parameters have been set correctly and
starts the object working. It returns non-zero on error, setting
\verb+im_error_string()+.
\subsubsection{Use}
The object is now fully working. You can read results from it, or pass it on
other objects. When you're finished with it, drop your reference to end its
life.
\begin{verbatim}
g_object_unref( object );
\end{verbatim}
\subsection{Convenience functions}
Two functions simplify building and printing objects.
\verb+vips_object_new_from_string()+ makes a new object which is a subclass of
a named base class.
\begin{verbatim}
VipsObject *
vips_object_new_from_string(
const char *basename, const char *p );
\end{verbatim}
This is the function used by \verb+IM_INPUT_INTERPOLATE()+, for example, to
parse command-line arguments. The syntax is:
\begin{verbatim}
nickname [ ( required-arg1,
...
required-argn,
optional-arg-name = value,
...
optional-argm-name = value ) ]
\end{verbatim}
So values for all the required arguments, in the correct order, then name =
value for all the optional arguments you want to set. Parameters may be
enclosed in round or curly braces.
\verb+vips_object_to_string()+ is the exact opposite: it generates the
construct string for any constructed
\verb+VipsObject+.
\verb+vips_object_new()+ wraps up the business of creating and checking an
object. It makes the object, uses the supplied function to attach any
arguments, then builds the object and returns NULL on failure or the new
object on success.
A switch to the \verb+vips+ command-line program is handy for listing subtypes
of \verb+VipsObject+. Try:
\begin{verbatim}
$ vips list classes
\end{verbatim}

View File

@ -1,100 +0,0 @@
\section{Introduction}
\mylabel{sec:oper}
This chapter explains how to write image processing operations using the
VIPS image I/O (input-output) system. For background, you should probably
take a look at \pref{sec:appl}. This is supposed to be a tutorial, if you
need detailed information on any particular function, use the on-line UNIX
manual pages.
\subsection{Why use VIPS?}
If you use the VIPS image I/O system, you get a number of benefits:
\begin{description}
\item[Threading]
If your computer has more than one CPU, the VIPS I/O system will automatically
split your image processing operation into separate threads (provided you
use PIO, see below). You should get an approximately linear speed-up as
you add more CPUs.
\item[Pipelining]
Provided you use PIO (again, see below), VIPS can automatically join
operations together. A sequence of image processing operations will all
execute together, with image data flowing through the processing pipeline
in small pieces. This makes it possible to perform complex processing on
very large images with no need to worry about storage management.
\item[Composition]
Because VIPS can efficiently compose image processing operations, you can
implement your new operation in small, reusable, easy-to-understand
pieces. VIPS already has a lot of these: many new operations can be
implemented by simply composing existing operations.
\item[Large files]
Provided you use PIO and as long as the underlying OS supports large files
(that is, files larger than 2GB), VIPS operations can work on files larger
than can be addressed with 32 bits on a plain 32-bit machine. VIPS operations
only see 32 bit addresses; the VIPS I/O system transparently maps these to
64 bit operations for I/O. Large file support is included on most machines
after about 1998.
\item[Abstraction]
VIPS operations see only arrays of numbers in native format. Details of
representation (big/little endian, VIPS/TIFF/JPEG file format, etc.) are
hidden from you.
\item[Interfaces]
Once you have your image processing operation implemented, it automatically
appears in all of the VIPS interfaces. VIPS comes with a GUI (\nip{}), a
UNIX command-line interface (\vips{}) and a C++ and Python API.
\item[Portability]
VIPS operations can be compiled on most unixes, Mac OS X and Windows NT, 2000
and XP without modification. Mostly.
\end{description}
\subsection{I/O styles}
The I/O system supports three styles of input-output.
\begin{description}
\item[Whole-image I/O (WIO)]
This style is a largely a left-over from VIPS 6.x. WIO image-processing
operations have all of the input image given to them in a large memory
array. They can read any of the input pels at will with simple pointer
arithmetic.
\item[Partial-image I/O (PIO)]
In this style operations only have a small part of the input image available
to them at any time. When PIO operations are joined together into a pipeline,
images flow through them in small pieces, with all the operations in a
pipeline executing at the same time.
\item[In-place]
The third style allows pels to be read and written anywhere in
the image at any time, and is used by the VIPS in-place operations, such
as \verb+im_fastline()+. You should only use it for operations which would
just be impossibly inefficient to write with either of the other two styles.
\end{description}
WIO operations are easy to program, but slow and inflexible when images
become large. PIO operations are harder to program, but scale well as images
become larger, and are automatically parallelized by the VIPS I/O system.
If you can face it, and if your algorithm can be expressed in this way, you
should write your operations using PIO. Whichever you choose, applications
which call your operation will see no difference, except in execution speed.
If your image processing operation performs no coordinate transformations,
that is, if your output image is the same size as your input image or images,
and if each output pixel depends only upon the pixel at the corresponding
position in the input images, then you can use the \verb+im_wrapone()+
and \verb+im_wrapmany()+ operations. These take a simple buffer-processing
operation supplied by you and wrap it up as a full-blown PIO operation.
See~\pref{sec:wrapone}.

View File

@ -1,889 +0,0 @@
\section{VIPS packages}
\mylabel{sec:packages}
\subsection{Arithmetic}
See \fref{fg:arithmetic}.
Arithmetic functions work on images as if each band element were a separate
number. All operations are point-to-point --- each output element depends
exactly upon the corresponding input element. All (except in a few cases
noted in the manual pages) will work with images of any type (or any mixture
of types), of any size and of any number of bands.
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 \verb+IM_BANDFMT_UCHAR+
images together, for example, produces a \verb+IM_BANDFMT_USHORT+ image, and
taking the \verb+im_costra()+ of a \verb+IM_BANDFMT_USHORT+ image produces
a \verb+IM_BANDFMT_FLOAT+ image. The details of the type conversions are
in the manual pages.
\begin{fig2}
\begin{verbatim}
$ vips list arithmetic
im_abs - absolute value
im_acostra - acos of image (result in degrees)
im_add - add two images
im_asintra - asin of image (result in degrees)
im_atantra - atan of image (result in degrees)
im_avg - average value of image
im_point_bilinear - interpolate value at single point, linearly
im_bandmean - average image bands
im_ceil - round to smallest integal value not less than
im_cmulnorm - multiply two complex images, normalising output
im_costra - cos of image (angles in degrees)
im_cross_phase - phase of cross power spectrum of two complex images
im_deviate - standard deviation of image
im_divide - divide two images
im_exp10tra - 10^pel of image
im_expntra - x^pel of image
im_expntra_vec - [x,y,z]^pel of image
im_exptra - e^pel of image
im_fav4 - average of 4 images
im_floor - round to largest integal value not greater than
im_gadd - calculate a*in1 + b*in2 + c = outfile
im_invert - photographic negative
im_lintra - calculate a*in + b = outfile
im_linreg - pixelwise linear regression
im_lintra_vec - calculate a*in + b -> out, a and b vectors
im_litecor - calculate max(white)*factor*(in/white), if clip == 1
im_log10tra - log10 of image
im_logtra - ln of image
im_max - maximum value of image
im_maxpos - position of maximum value of image
im_maxpos_avg - position of maximum value of image, averaging in case of draw
im_maxpos_vec - position and value of n maxima of image
im_measure - measure averages of a grid of patches
im_min - minimum value of image
im_minpos - position of minimum value of image
im_minpos_vec - position and value of n minima of image
im_multiply - multiply two images
im_powtra - pel^x ofbuildimage
im_powtra_vec - pel^[x,y,z] of image
im_remainder - remainder after integer division
im_remainderconst - remainder after integer division by a constant
im_remainderconst_vec - remainder after integer division by a vector of constants
im_rint - round to nearest integal value
im_sign - unit vector in direction of value
im_sintra - sin of image (angles in degrees)
im_stats - many image statistics in one pass
im_subtract - subtract two images
im_tantra - tan of image (angles in degrees)
\end{verbatim}
\caption{Arithmetic functions}
\label{fg:arithmetic}
\end{fig2}
\subsection{Relational}
See \fref{fg:relational}.
Relational functions compare images to other images or to constants. They
accept any image or pair of images (provided they are the same size and
have the same number of bands --- their types may differ) and produce a
\verb+IM_BANDFMT_UCHAR+ image with the same number of bands as the input
image, with 255 in every band element for which the condition is true and
0 elsewhere.
They may be combined with the boolean functions to form complex relational
conditions. Use \verb+im_max()+ (or \verb+im_min()+) to find out if a
condition is true (or false) for a whole image.
\begin{fig2}
\begin{verbatim}
$ vips list relational
im_blend - use cond image to blend between images in1 and in2
im_equal - two images equal in value
im_equal_vec - image equals doublevec
im_equalconst - image equals const
im_ifthenelse - use cond image to choose pels from image in1 or in2
im_less - in1 less than in2 in value
im_less_vec - in less than doublevec
im_lessconst - in less than const
im_lesseq - in1 less than or equal to in2 in value
im_lesseq_vec - in less than or equal to doublevec
im_lesseqconst - in less than or equal to const
im_more - in1 more than in2 in value
im_more_vec - in more than doublevec
im_moreconst - in more than const
im_moreeq - in1 more than or equal to in2 in value
im_moreeq_vec - in more than or equal to doublevec
im_moreeqconst - in more than or equal to const
im_notequal - two images not equal in value
im_notequal_vec - image does not equal doublevec
im_notequalconst - image does not equal const
\end{verbatim}
\caption{Relational functions}
\label{fg:relational}
\end{fig2}
\subsection{Boolean}
See \fref{fg:boolean}.
The boolean functions perform boolean arithmetic on pairs of
\verb+IM_BANDFMT_UCHAR+ images. They are useful for combining the results of
the relational and morphological functions. You can use
\verb+im_eorconst()+ with 255 as \verb+im_not()+.
\begin{fig2}
\begin{verbatim}
$ vips list boolean
im_andimage - bitwise and of two images
im_andimageconst - bitwise and of an image with a constant
im_andimage_vec - bitwise and of an image with a vector constant
im_orimage - bitwise or of two images
im_orimageconst - bitwise or of an image with a constant
im_orimage_vec - bitwise or of an image with a vector constant
im_eorimage - bitwise eor of two images
im_eorimageconst - bitwise eor of an image with a constant
im_eorimage_vec - bitwise eor of an image with a vector constant
im_shiftleft - shift integer image n bits to left
im_shiftright - shift integer image n bits to right
\end{verbatim}
\caption{Boolean functions}
\label{fg:boolean}
\end{fig2}
\subsection{Colour}
\label{sec:colour}
See \fref{fg:colour}.
The colour functions can be divided into two main types. First, functions to
transform images between the different colour spaces supported by VIPS:
\verb+RGB+ (also referred to as \verb+disp+), \verb+sRGB+, \verb+XYZ+,
\verb+Yxy+, \verb+Lab+, \verb+LabQ+, \verb+LabS+, \verb+LCh+ and
\verb+UCS+), and second, functions for calculating colour difference
metrics. Figure~\ref{fg:convert} shows how the VIPS colour spaces
interconvert.
\begin{fig2}
\figw{5in}{interconvert.png}
\caption{VIPS colour space conversion}
\label{fg:convert}
\end{fig2}
The colour spaces supported by VIPS are:
\begin{description}
\item[\texttt{LabQ}]
This is the principal VIPS colorimetric storage format. See the
man page for \verb+im_LabQ2Lab()+ for an explanation. You cannot perform
calculations on \verb+LabQ+ images. They are for storage only. Also refered
to as \verb+LABPACK+.
\item[\texttt{LabS}]
This format represents coordinates in \cielab{} space as a three-
band \verb+IM_BANDFMT_SHORT+ image, scaled to fit the full range of bits. It is
the best format for computation, being relatively compact, quick, and
accurate. Colour values expressed in this way are hard to visualise.
\item[\texttt{Lab}]
\verb+Lab+ colourspace represents \cielab{} colour values with a three-band
\verb+IM_BANDFMT_FLOAT+ image. This is the simplest format for general work: adding the
constant 50 to the L channel, for example, has the expected result.
\item[\texttt{XYZ}]
\ciexyz{} colour space represented as a three-band \verb+IM_BANDFMT_FLOAT+
image.
\item[\texttt{XYZ}]
\cieyxy{} colour space represented as a three-band \verb+IM_BANDFMT_FLOAT+
image.
\item[\texttt{RGB}]
(also refered to as \verb+disp+) This format is similar to the RGB colour
systems used in other packages. If you want to export your image to a PC,
for example, convert your colorimetric image to \verb+RGB+, then turn it
to TIFF with \verb+im_vips2tiff()+. You need to supply a structure which
characterises your display. See the manual page for \verb+im_col_XYZ2rgb()+
for hints on these guys.
VIPS also supports \verb+sRGB+. This is a version of RGB with a carefully
defined and standard conversion from XYZ. See:
\begin{verbatim}
http://www.color.org/
\end{verbatim}
\item[\texttt{LCh}]
Like \verb+Lab+, but rectangular $ab$ coordinates are replaced with polar $Ch$
(Chroma and hue) coordinates. Hue angles are expressed in degrees.
\item[\texttt{UCS}]
A colour space based on the CMC(1:1) colour difference measurement. This
is a highly uniform colour space, much better than \cielab{} for expressing
small differences. Conversions to and from \verb+UCS+ are extremely slow.
\end{description}
All VIPS colourspaces assume a D65 illuminant.
The colour-difference functions calculate either $\Delta{}E$ \cielab{} (1976
or 2000) or $\Delta{}E$ CMC(1:1) on two images in \verb+Lab+, \verb+XYZ+
or \verb+disp+ colour space.
\begin{fig2}
\begin{verbatim}
$ vips list colour
im_LCh2Lab - convert LCh to Lab
im_LCh2UCS - convert LCh to UCS
im_Lab2LCh - convert Lab to LCh
im_Lab2LabQ - convert Lab to LabQ
im_Lab2LabS - convert Lab to LabS
im_Lab2UCS - convert Lab to UCS
im_Lab2XYZ - convert D65 Lab to XYZ
im_Lab2XYZ_temp - convert Lab to XYZ, with a specified colour temperature
im_Lab2disp - convert Lab to displayable
im_LabQ2LabS - convert LabQ to LabS
im_LabQ2Lab - convert LabQ to Lab
im_LabQ2XYZ - convert LabQ to XYZ
im_LabQ2disp - convert LabQ to displayable
im_LabS2LabQ - convert LabS to LabQ
im_LabS2Lab - convert LabS to Lab
im_UCS2LCh - convert UCS to LCh
im_UCS2Lab - convert UCS to Lab
im_UCS2XYZ - convert UCS to XYZ
im_XYZ2Lab - convert D65 XYZ to Lab
im_XYZ2Lab_temp - convert XYZ to Lab, with a specified colour temperature
im_XYZ2UCS - convert XYZ to UCS
im_XYZ2Yxy - convert XYZ to Yxy
im_XYZ2disp - convert XYZ to displayble
im_XYZ2sRGB - convert XYZ to sRGB
im_Yxy2XYZ - convert Yxy to XYZ
im_dE00_fromLab - calculate delta-E CIE2000 for two Lab images
im_dECMC_fromLab - calculate delta-E CMC(1:1) for two Lab images
im_dECMC_fromdisp - calculate delta-E CMC(1:1) for two displayable images
im_dE_fromLab - calculate delta-E for two Lab images
im_dE_fromXYZ - calculate delta-E for two XYZ images
im_dE_fromdisp - calculate delta-E for two displayable images
im_disp2Lab - convert displayable to Lab
im_disp2XYZ - convert displayable to XYZ
im_float2rad - convert float to Radiance packed
im_icc_ac2rc - convert LAB from AC to RC using an ICC profile
im_icc_export - convert a float LAB to an 8-bit device image with an ICC profile
im_icc_export_depth - convert a float LAB to device space with an ICC profile
im_icc_import - convert a device image to float LAB with an ICC profile
im_icc_import_embedded - convert a device image to float LAB using the embedded profile
im_icc_present - test for presence of ICC library
im_icc_transform - convert between two device images with a pair of ICC profiles
im_lab_morph - morph colourspace of a LAB image
im_rad2float - convert Radiance packed to float
im_sRGB2XYZ - convert sRGB to XYZ
\end{verbatim}
\caption{Colour functions}
\label{fg:colour}
\end{fig2}
\subsection{Conversion}
See \fref{fg:conversion}.
These functions may be split into three broad groups: functions which convert
between the VIPS numeric formats (\verb+im_clip2fmt()+, for example, converts
an image of any type to the specified \verb+IM_BANDFMT+), functions
supporting complex arithmetic (\verb+im_c2amph()+, for example, converts
a complex image from rectangular to polar co ordinates) and functions
which perform some simple geometric conversion (\verb+im_extract()+ forms
a sub-image).
\verb+gbandjoin+ and the C function \verb+im_gbandjoin()+ will do a bandwise
join of many images at the same time. See the manual pages.
\begin{fig2}
\begin{verbatim}
$ vips list conversion
im_bandjoin - bandwise join of two images
im_bernd - extract from pyramid as jpeg
im_black - generate black image
im_c2amph - convert real and imaginary to phase and amplitude
im_c2imag - extract imaginary part of complex image
im_c2ps - find power spectrum of complex image
im_c2real - extract real part of complex image
im_c2rect - convert phase and amplitude to real and imaginary
im_clip2c - convert to signed 8-bit integer
im_clip2cm - convert to complex
im_clip2d - convert to double-precision float
im_clip2dcm - convert to double complex
im_clip2f - convert to single-precision float
im_clip2fmt - convert image format to ofmt
im_clip2i - convert to signed 32-bit integer
im_clip2s - convert to signed 16-bit integer
im_clip2ui - convert to unsigned 32-bit integer
im_clip2us - convert to unsigned 16-bit integer
im_clip - convert to unsigned 8-bit integer
im_copy - copy image
im_copy_morph - copy image, setting pixel layout
im_copy_swap - copy image, swapping byte order
im_copy_set - copy image, setting informational fields
im_copy_set_meta - copy image, setting a meta field
im_extract_area - extract area
im_extract_areabands - extract area and bands
im_extract_band - extract band
im_extract_bands - extract several bands
im_extract - extract area/band
im_falsecolour - turn luminance changes into chrominance changes
im_fliphor - flip image left-right
im_flipver - flip image top-bottom
im_gbandjoin - bandwise join of many images
im_grid - chop a tall thin image into a grid of images
im_insert - insert sub-image into main image at position
im_insert_noexpand - insert sub-image into main image at position, no expansion
im_lrjoin - join two images left-right
im_mask2vips - convert DOUBLEMASK to VIPS image
im_msb - convert to uchar by discarding bits
im_msb_band - convert to single band uchar by discarding bits
im_print - print string to stdout
im_recomb - linear recombination with mask
im_replicate - replicate an image horizontally and vertically
im_ri2c - join two non-complex images to form complex
\end{verbatim}
\caption{Conversion functions}
\label{fg:conversion}
\end{fig2}
\begin{fig2}
\begin{verbatim}
im_rot180 - rotate image 180 degrees
im_rot270 - rotate image 270 degrees clockwise
im_rot90 - rotate image 90 degrees clockwise
im_scale - scale image linearly to fit range 0-255
im_scaleps - logarithmic scale of image to fit range 0-255
im_rightshift_size - decrease size by a power-of-two factor
im_slice - slice an image using two thresholds
im_subsample - subsample image by integer factors
im_system - run command on image
im_tbjoin - join two images top-bottom
im_text - generate text image
im_thresh - slice an image at a threshold
im_vips2mask - convert VIPS image to DOUBLEMASK
im_wrap - shift image origin, wrapping at sides
im_zoom - simple zoom of an image by integer factors
\end{verbatim}
\caption{Conversion functions (cont.)}
\end{fig2}
\subsection{Matricies}
See \fref{fg:matricies}.
VIPS uses matricies for morphological operations, for convolutions, and
for some colour-space conversions. There are two types of matrix: integer
(\verb+INTMASK+) and double precision floating point (\verb+DOUBLEMASK+).
For convenience, both types are stored in files as ASCII. The first
line of the file should start with the matrix dimensions, width first,
then on the same line an optional scale and offset. The two size fields
should be integers; the scale and offset may be floats. Subsequent lines
should contain the matrix elements, one row per line. The scale and
offset are the conventional ones used to represent non-integer values in
convolution masks --- in other words:
\[
result = {value \over scale} + offset
\]
If the scale and offset are missing, they default to 1.0 and 0.0. See the
sections on convolution for more on the use of these fields. So as an example,
a 4 by 4 identity matrix would be stored as:
\begin{verbatim}
4 4
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
\end{verbatim}
And a 3 by 3 mask for block averaging with convolution might be stored as:
\begin{verbatim}
3 3 9 0
1 1 1
1 1 1
1 1 1
\end{verbatim}
\noindent
(in other words, sum all the pels in every 3 by 3 area, and divide by 9).
This matrix contains only integer elements and so could be used as an
argument to functions expecting both \verb+INTMASK+ and \verb+DOUBLEMASK+
matricies. However, masks containing floating-point values (such as the
output of \verb+im_matinv()+) can only be used as arguments to functions
expecting \verb+DOUBLEMASK+s.
A set of functions for mask input and output are also available for
C-programmers --- see the manual pages for \verb+im_read_dmask()+. For
other matrix functions, see also the convolution sections and the arithmetic
sections.
\begin{fig2}
\begin{verbatim}
$ vips list matrix
im_matcat - append matrix in2 to the end of matrix in1
im_matinv - invert matrix
im_matmul - multiply matrix in1 by matrix in2
im_mattrn - transpose matrix
\end{verbatim}
\caption{Matrix functions}
\label{fg:matricies}
\end{fig2}
\subsection{Convolution}
See \fref{fg:convolution}.
The functions available in the convolution package can be split into five
main groups.
First, are the convolution functions. The most useful function is
\verb+im_conv()+ which will convolve any non-complex type with an
\verb+INTMASK+ matrix. The output image will have the same size, type, and
number of bands as the input image. Of the other \verb+im_conv()+ functions,
functions whose name ends in \verb+_raw+ do not add a black border around the
output image, functions ending in \verb+f+ use a \verb+DOUBLEMASK+ matrix
and write float (or double) output, and functions containing \verb+sep+
are for seperable convolutions. \verb+im_compass()+, \verb+im_lindetect()+
and \verb+im_gradient()+ convolve with rotating masks. \verb+im_embed()+
is used by the convolution functions to add the border to the output.
Next, are the build functions. \verb+im_gauss_*mask()+ and its ilk
generate gaussian masks, \verb+im_log_*mask()+ generate logs of Laplacians.
\verb+im_addgnoise()+ and \verb+im_gaussnoise()+ create or add gaussian
noise to an image.
Two functions do correlation: \verb+im_fastcor()+ does a quick and dirty
correlation, \verb+im_spcor()+ calculates true spatial correlation, and is
rather slow.
Some functions are provided for analysing images: \verb+im_zerox()+ counts
zero-crossing points in an image, \verb+im_mpercent()+ finds a threshold
that will isolate a percentage of points in an image.
Finally, \verb+im_resize_linear()+ and \verb+im_shrink()+ do as you would
expect.
\begin{fig2}
\begin{verbatim}
$ vips list convolution
im_addgnoise - add gaussian noise with mean 0 and std. dev. sigma
im_compass - convolve with 8-way rotating integer mask
im_contrast_surface - find high-contrast points in an image
im_contrast_surface_raw - find high-contrast points in an image
im_conv - convolve
im_conv_raw - convolve, no border
im_convf - convolve, with DOUBLEMASK
im_convf_raw - convolve, with DOUBLEMASK, no border
im_convsep - seperable convolution
im_convsep_raw - seperable convolution, no border
im_convsepf - seperable convolution, with DOUBLEMASK
im_convsepf_raw - seperable convolution, with DOUBLEMASK, no border
im_convsub - convolve uchar to uchar, sub-sampling by xskip, yskip
im_dmask_xsize - horizontal size of a doublemask
im_dmask_ysize - vertical size of a doublemask
im_embed - embed in within a set of borders
im_fastcor - fast correlate in2 within in1
im_fastcor_raw - fast correlate in2 within in1, no border
im_gauss_dmask - generate gaussian DOUBLEMASK
im_gauss_imask - generate gaussian INTMASK
im_gauss_imask_sep - generate separable gaussian INTMASK
im_gaussnoise - generate image of gaussian noise with specified statistics
im_grad_x - horizontal difference image
im_grad_y - vertical difference image
im_gradcor - non-normalised correlation of gradient of in2 within in1
im_gradcor_raw - non-normalised correlation of gradient of in2 within in1, no padding
im_gradient - convolve with 2-way rotating mask
im_imask_xsize - horizontal size of an intmask
im_imask_ysize - vertical size of an intmask
im_rank_image - point-wise pixel rank
im_lindetect - convolve with 4-way rotating mask
im_log_dmask - generate laplacian of gaussian DOUBLEMASK
im_log_imask - generate laplacian of gaussian INTMASK
im_maxvalue - point-wise maximum value
im_mpercent - find threshold above which there are percent values
im_phasecor_fft - non-normalised correlation of gradient of in2 within in1
im_rank - rank filter nth element of xsize/ysize window
im_rank_raw - rank filter nth element of xsize/ysize window, no border
im_read_dmask - read matrix of double from file
im_resize_linear - resize to X by Y pixels with linear interpolation
im_rotate_dmask45 - rotate DOUBLEMASK clockwise by 45 degrees
im_rotate_dmask90 - rotate DOUBLEMASK clockwise by 90 degrees
im_rotate_imask45 - rotate INTMASK clockwise by 45 degrees
im_rotate_imask90 - rotate INTMASK clockwise by 90 degrees
im_sharpen - sharpen high frequencies of L channel of LabQ
im_shrink - shrink image by xfac, yfac times
im_spcor - normalised correlation of in2 within in1
im_spcor_raw - normalised correlation of in2 within in1, no black padding
im_stretch3 - stretch 3%, sub-pixel displace by xdisp/ydisp
im_zerox - find +ve or -ve zero crossings in image
\end{verbatim}
\caption{Convolution functions}
\label{fg:convolution}
\end{fig2}
\subsection{In-place operations}
\label{sec:inplace}
See \fref{fg:inplace}.
A few of the in-place operations are available from the command-line. Most are
not.
\begin{fig2}
\begin{verbatim}
$ vips list inplace
im_circle - plot circle on image
im_flood_blob_copy - flood while pixel == start pixel
im_insertplace - draw image sub inside image main at position (x,y)
im_line - draw line between points (x1,y1) and (x2,y2)
im_lineset - draw line between points (x1,y1) and (x2,y2)
\end{verbatim}
\caption{In-place operations}
\label{fg:inplace}
\end{fig2}
\subsection{Frequency filtering}
See \fref{fg:freq}.
The basic Fourier functions are \verb+im_fwfft()+ and
\verb+im_invfft()+, which calculate the fast-fourier transform and inverse
transform of an image. Also \verb+im_invfftr()+, which just returns the real
part of the inverse transform.
The Fourier image has its origin at pel (0,0) ---
for viewing, use \verb+im_rotquad()+ to move the origin to the centre of
the image.
Once an image is in the frequency domain, it can be filtered by multiplying
it with a mask image. The VIPS mask generator is \verb+im_create_fmask()+
see the manual page for details of the arguments, but it will create low
pass, high pass, ring pass and band pass filters, which may each be ideal,
Gaussian or Butterworth. There is also a fractal mask option.
The other functions in the package build on these base
facilities. \verb+im_freqflt()+ transforms an input image to
Fourier space, multiplies it by a mask image, and transforms it back
again. \verb+im_flt_image_freq()+ will create a mask image of the correct
size for you, and call \verb+im_freqflt()+. \verb+im_disp_ps()+ will call
the right combinations of functions to make a displayable power spectrum
for an image.
\begin{fig2}
\begin{verbatim}
$ vips list freq_filt
im_create_fmask - create frequency domain filter mask
im_disp_ps - make displayable power spectrum
im_flt_image_freq - frequency domain filter image
im_fractsurf - generate a fractal surface of given dimension
im_freqflt - frequency-domain filter of in with mask
im_fwfft - forward fast-fourier transform
im_rotquad - rotate image quadrants to move origin to centre
im_invfft - inverse fast-fourier transform
im_invfftr - real part of inverse fast-fourier transform
\end{verbatim}
\caption{Fourier functions}
\label{fg:freq}
\end{fig2}
\subsection{Histograms and LUTs}
See \fref{fg:hist}.
VIPS represents histograms and look-up tables in the same way --- as images.
They should have either \verb+Xsize+ or \verb+Ysize+ set to 1, and the
other dimension set to the number of elements in the table. The table can be
of any size, have any band format, and have any number of bands.
Use \verb+im_histgr()+ to find the histogram of an image. Use
\verb+im_histnD()+ to find the n-dimensional histogram of an n-band
image. Perform operations on histograms with \verb+im_histcum()+,
\verb+im_histnorm()+, \verb+im_histspec()+, \verb+im_invertlut()+. Visualise
histograms with \verb+im_histplot()+. Use a histogram (or LUT) to transform
an image with \verb+im_maplut()+. Build a histogram from scratch with
\verb+im_identity()+ or \verb+im_identity_ushort()+.
Use \verb+im_lhist*()+ for local histogram equalisation, and
\verb+im_stdif*()+ for statisticaol differencing. The \verb+im_tone_*()+
functions are for operations on the L channel of a LAB image. Other
functions are useful combinations of these basic operations.
\begin{fig2}
\begin{verbatim}
$ vips list histograms_lut
im_gammacorrect - gamma-correct image
im_heq - histogram-equalise image
im_hist - find and graph histogram of image
im_histcum - turn histogram to cumulative histogram
im_histeq - form histogram equalistion LUT
im_histgr - find histogram of image
im_histnD - find 1D, 2D or 3D histogram of image
im_histnorm - form normalised histogram
im_histplot - plot graph of histogram
im_histspec - find histogram which will make pdf of in match ref
im_hsp - match stats of in to stats of ref
im_identity - generate identity histogram
im_identity_ushort - generate ushort identity histogram
im_ismonotonic - test LUT for monotonicity
im_lhisteq - local histogram equalisation
im_lhisteq_raw - local histogram equalisation, no border
im_invertlut - generate correction table from set of measures
im_buildlut - generate LUT table from set of x/y positions
im_maplut - map image through LUT
im_project - find horizontal and vertical projections of an image
im_stdif - statistical differencing
im_stdif_raw - statistical differencing, no border
im_tone_analyse - analyse in and create LUT for tone adjustment
im_tone_build - create LUT for tone adjustment of LabS images
im_tone_build_range - create LUT for tone adjustment
im_tone_map - map L channel of LabS or LabQ image through LUT
\end{verbatim}
\caption{Histogram/LUT functions}
\label{fg:hist}
\end{fig2}
\subsection{Morphology}
See \fref{fg:morph}.
The morphological functions are used on one-band \verb+IM_BANDFMT_UCHAR+ binary
images (images containing only zero and not-zero). They search images
for particular patterns of pixels (specified with the mask argument),
either adding or removing pixels when they find a match. They are useful
for cleaning up images --- for example, you might threshold an image, and
then use one of the morphological functions to remove all single isolated
pixels from the result.
If you combine the morphological operators with the mask rotators
(\verb+im_rotate_imask45()+, for example) and apply them repeatedly, you
can achieve very complicated effects: you can thin, prune, fill, open edges,
close gaps, and many others. For example, see `Fundamentals of Digital
Image Processing' by A. Jain, pp 384-388, Prentice-Hall, 1989 for more ideas.
Beware that VIPS reverses the usual image processing convention, by assuming
white objects on a black background.
The mask you give to the morphological functions should contain only the
values 0 (for background), 128 (for don't care) and 255 (for object). The
mask must have odd length sides --- the origin of the mask is taken to be
the centre value. For example, the mask:
\begin{verbatim}
3 3
128 255 128
255 0 255
128 255 128
\end{verbatim}
\noindent
applied to an image with \verb+im_erode()+, will find all black pixels
4-way connected with white pixels. Essentially, \verb+im_dilate()+
sets pixels in the output if any part of the mask matches, whereas
\verb+im_erode()+ sets pixels only if all of the mask matches.
The \verb+_raw()+ version of the functions do not add a black border to the
output. \verb+im_cntlines()+ and \verb+im_profile+ are occasionally useful for
analysing results.
See the boolean operations \verb+im_and()+, \verb+im_or()+ and
\verb+im_eor()+ for analogues of the usual set difference and set
union operations.
\begin{fig2}
\begin{verbatim}
$ vips list morphology
im_cntlines - count horizontal or vertical lines
im_dilate - dilate image with mask, adding a black border
im_dilate_raw - dilate image with mask
im_erode - erode image with mask, adding a black border
im_erode_raw - erode image with mask
im_profile - find first horizontal/vertical edge
\end{verbatim}
\caption{Morphological functions}
\label{fg:morph}
\end{fig2}
\subsection{Mosaicing}
See \fref{fg:mosaicing}.
These functions are useful for joining many small images together to make one
large image. They can cope with unstable contrast, and arbitary sub-image
layout, but will not do any geometric correction. The mosaicing functions
can be grouped into layers:
The lowest level functions are \verb+im_correl()+. and \verb+im_affine()+.
\verb+im_correl()+ searches a large image for a small sub-image, returning
the position of the best sub-image match. \verb+im_affine()+ performs
a general affine transform on an image: that is, any transform in which
parallel lines remain parallel.
Next, \verb+im_lrmerge()+ and \verb+im_tbmerge()+ blend two images together
left-right or up-down.
Next up are \verb+im_lrmosaic()+ and \verb+im_tbmosaic()+. These use the
two low-level merge operations to join two images given just an approximate
overlap as a start point. Optional extra parameters let you do 'balancing'
too: if your images have come from a source where there is no precise
control over the exposure (for example, images from a tube camera, or a
set of images scanned from photographic sources), \verb+im_lrmosaic()+
and \verb+im_tbmosaic()+ will adjust the contrast of the left image to
match the right, the right to the left, or both to some middle value.
The functions \verb+im_lrmosaic1()+ and \verb+im_tbmosaic1()+ are first-order
analogues of the basic mosaic functions: they take two tie-points and use
them to rotate and scale the right-hand or bottom image before starting to join.
Finally, \verb+im_global_balance()+ can be used to re-balance a mosaic
which has been assembled with these functions. It will generally do a
better job than the low-level balancer built into \verb+im_lrmosaic()+
and \verb+im_tbmosaic()+. See the man page. \verb+im_remosaic()+ uses the same
techniques, but will reassemble the image from a different set of source
images.
\begin{fig2}
\begin{verbatim}
$ vips list mosaicing
im_align_bands - align the bands of an image
im_correl - search area around sec for match for area around ref
im__find_lroverlap - search for left-right overlap of ref and sec
im__find_tboverlap - search for top-bottom overlap of ref and sec
im_global_balance - automatically rebuild mosaic with balancing
im_global_balancef - automatically rebuild mosaic with balancing, float output
im_lrmerge - left-right merge of in1 and in2
im_lrmerge1 - first-order left-right merge of ref and sec
im_lrmosaic - left-right mosaic of ref and sec
im_lrmosaic1 - first-order left-right mosaic of ref and sec
im_match_linear - resample ref so that tie-points match
im_match_linear_search - search sec, then resample so that tie-points match
im_maxpos_subpel - subpixel position of maximum of (phase correlation) image
im_remosaic - automatically rebuild mosaic with new files
im_tbmerge - top-bottom merge of in1 and in2
im_tbmerge1 - first-order top-bottom merge of in1 and in2
im_tbmosaic - top-bottom mosaic of in1 and in2
im_tbmosaic1 - first-order top-bottom mosaic of ref and sec
\end{verbatim}
caption{Mosaic functions}
\label{fg:mosaicing}
\end{fig2}
\subsection{CImg functions}
See \fref{fg:cimg}.
These operations wrap the anisotropic blur function from the CImg library.
They are useful for removing noise from images.
\begin{fig2}
\begin{verbatim}
$ vips list cimg
im_greyc - noise-removing filter
im_greyc_mask - noise-removing filter, with a mask
\end{verbatim}
\caption{CImg functions}
\label{fg:cimg}
\end{fig2}
\subsection{Other}
See \fref{fg:other}.
These functions generate various test images. You can combine them with
the arithmetic and rotate functions to build more complicated images.
The \verb+im_benchmark*()+ operations are for testing the VIPS SMP system.
\begin{fig2}
\begin{verbatim}
$ vips list other
im_benchmark - do something complicated for testing
im_benchmark2 - do something complicated for testing
im_benchmarkn - do something complicated for testing
im_eye - generate IM_BANDFMT_UCHAR [0,255] frequency/amplitude image
im_grey - generate IM_BANDFMT_UCHAR [0,255] grey scale image
im_feye - generate IM_BANDFMT_FLOAT [-1,1] frequency/amplitude image
im_fgrey - generate IM_BANDFMT_FLOAT [0,1] grey scale image
im_fzone - generate IM_BANDFMT_FLOAT [-1,1] zone plate image
im_make_xy - generate image with pixel value equal to coordinate
im_zone - generate IM_BANDFMT_UCHAR [0,255] zone plate image
\end{verbatim}
\caption{Other functions}
\label{fg:other}
\end{fig2}
\subsection{IO functions}
See \fref{fg:io}.
These functions are related to the image IO system.
\begin{fig2}
\begin{verbatim}
$ vips list iofuncs
im_binfile - open a headerless binary file
im_cache - cache results of an operation
im_guess_prefix - guess install area
im_guess_libdir - guess library area
im_header_get_type - return field type
im_header_int - extract int fields from header
im_header_double - extract double fields from header
im_header_string - extract string fields from header
im_version - VIPS version number
im_version_string - VIPS version string
\end{verbatim}
\caption{IO functions}
\label{fg:io}
\end{fig2}
\subsection{Format functions}
See \fref{fg:format}.
These functions convert to and from various image formats. See
\pref{sec:format} for a nice API over these. VIPS can read more than these
formats, see the man page for \verb+VipsFormat+.
\begin{fig2}
\begin{verbatim}
$ vips list format
im_csv2vips - read a file in csv format
im_jpeg2vips - convert from jpeg
im_magick2vips - load file with libMagick
im_png2vips - convert PNG file to VIPS image
im_exr2vips - convert an OpenEXR file to VIPS
im_ppm2vips - read a file in pbm/pgm/ppm format
im_analyze2vips - read a file in analyze format
im_tiff2vips - convert TIFF file to VIPS image
im_vips2csv - write an image in csv format
im_vips2jpeg - convert to jpeg
im_vips2mimejpeg - convert to jpeg as mime type on stdout
im_vips2png - convert VIPS image to PNG file
im_vips2ppm - write a file in pbm/pgm/ppm format
im_vips2tiff - convert VIPS image to TIFF file
\end{verbatim}
\caption{Format functions}
\label{fg:format}
\end{fig2}
\subsection{Resample functions}
See \fref{fg:resample}.
These functions resample images with various interpolators.
\begin{fig2}
\begin{verbatim}
$ vips list resample
im_affine - affine transform
im_affinei - affine transform
im_affinei_all - affine transform of whole image
im_similarity_area - output area xywh of similarity transformation
im_similarity - similarity transformation
\end{verbatim}
\caption{Resample functions}
\label{fg:resample}
\end{fig2}

View File

@ -1,854 +0,0 @@
\section{Programming PIO functions}
\label{sec:pio}
The VIPS PIO system has a number of advantages over WIO, as summarised in
the introduction. On the other hand, they are a bit more complicated.
\subsection{Easy PIO with \texttt{im\_wrapone()} and \texttt{im\_wrapmany()}}
\label{sec:wrapone}
PIO is a very general image IO system, and because of this flexibility,
can be complicated to program. As a convenience, VIPS offers an easy-to-use
layer over PIO with the funtions \verb+im_wrapone()+ and \verb+im_wrapmany()+.
If your image processing function is uninterested in coordinates, that is,
if your input and output images are the same size, and each output pixel
depends only upon the value of the corresponding pixel in the input image
or images, then these functions are for you.
Consider the \verb+invert()+ function of figure~\ref{fg:invert}. First,
we have to write the core of this as a buffer-processing function:
\begin{verbatim}
#include <stdio.h>
#include <stdlib.h>
#include <vips/vips.h>
/* p points to a buffer of pixels which
* need inverting, q points to the buffer
* we should write the result to, and n
* is the number of pels present.
*/
static void
invert_buffer( unsigned char *p,
unsigned char *q, int n )
{
int i;
for( i = 0; i < n; i++ )
q[i] = 255 - p[i];
}
\end{verbatim}
Now we have to wrap up this very primitive expression of the invert operation
as a PIO function. We use \verb+im_wrapone()+ to do this. It has type:
\begin{verbatim}
int
im_wrapone( IMAGE *in, IMAGE *out,
im_wrapone_fn fn, void *a, void *b )
\end{verbatim}
\noindent
where:
\begin{verbatim}
void
(*im_wrapone_fn)(void *in, void *out,
int n, void *a, void *b )
\end{verbatim}
\noindent
almost the same type as our buffer-processing function above. The values
\verb+a+ and \verb+b+ are carried around by VIPS for whatever use you
fancy. \verb+invert()+ can now be written as:
\begin{verbatim}
int
invert( IMAGE *in, IMAGE *out )
{
/* Check parameters.
*/
if( in->BandFmt != IM_BANDFMT_UCHAR ||
in->Bands != 1 ||
in->Coding != IM_CODING_NONE ) {
im_error( "invert", "bad image" );
return( -1 );
}
/* Set fields in output image.
*/
if( im_cp_desc( out, in ) )
return( -1 );
/* Process! We don't use either of the
* user parameters in this function,
* so leave them as NULL.
*/
if( im_wrapone( in, out,
(im_wrapone_fn) invert_buffer,
NULL, NULL ) )
return( -1 );
return( 0 );
}
\end{verbatim}
And that's all there is to it. This function will have all of the desirable
properties of PIO functions, while being as easy to program as the WIO
\verb+invert()+ earlier in this chapter.
This version of \verb+invert()+ is not very general: it will only accept
one-band unsigned char images. It is easy to modify for n-band images:
\begin{verbatim}
/* As before, but use one of the user
* parameters to pass in the number of
* bands in the image.
*/
static void
invert_buffer( unsigned char *p,
unsigned char *q, int n,
IMAGE *in )
{
int i;
int sz = n * in->Bands;
for( i = 0; i < sz; i++ )
q[i] = 255 - p[i];
}
\end{verbatim}
We must also modify \verb+invert()+:
\begin{verbatim}
int
invert( IMAGE *in, IMAGE *out )
{
/* Check parameters.
*/
if( in->BandFmt != IM_BANDFMT_UCHAR ||
in->Coding != IM_CODING_NONE ) {
im_error( "invert", "bad image" );
return( -1 );
}
/* Set fields in output image.
*/
if( im_cp_desc( out, in ) )
return( -1 );
/* Process! The first user-parameter
* is the number of bands involved.
*/
if( im_wrapone( in, out,
(im_wrapone_fn)invert_buffer,
in, NULL ) )
return( -1 );
return( 0 );
}
\end{verbatim}
There are two significant hidden traps here. First, inside the buffer
processing functions, you may only read the contents of the user parameters
\verb+a+ and \verb+b+, you may not write to them. This is because on a
multi-CPU machine, several copies of your buffer-processing functions will
be run in parallel --- if they all write to the same place, there will be
complete confusion. If you need writeable parameters (for example, to count
and report overflows), you can't use \verb+im_wrapone()+, you'll have to
use the PIO system in all its gory detail, see below.
Secondly, your buffer processing function may not be called immediately. VIPS
may decide to delay evaluation of your operation until long after the call
to \verb+invert()+ has returned. As a result, care is needed to ensure
that you never read anything in your buffer-processing function that may
have been freed. The best way to ensure this is to use the local resource
allocators, such as \verb+im_open_local()+ and \verb+im_malloc()+. This issue
is discussed at length in the sections below, and in \pref{sec:appl}.
\verb+im_wrapone()+ is for operations which take exactly one input image. VIPS
provides a second function, \verb+im_wrapmany()+, which works for any number
of input images. The type of \verb+im_wrapmany()+ is slightly different:
\begin{verbatim}
int
im_wrapmany( IMAGE **in, IMAGE *out,
im_wrapmany_fn fn, void *a, void *b )
\end{verbatim}
\noindent
\begin{verbatim}
void
(*im_wrapmany_fn)( void **in, void *out,
int n, void *a, void *b )
\end{verbatim}
\noindent
\verb+im_wrapmany()+ takes a \verb+NULL+-terminated array of input images,
and creates a \verb+NULL+-terminated array of buffers for the use of your
buffer processing function. A function to add two \verb+IM_BANDFMT_UCHAR+
images to make a \verb+IM_BANDFMT_UCHAR+ image might be written as:
\begin{verbatim}
static void
add_buffer( unsigned char **in,
unsigned short *out, int n,
IMAGE *in )
{
int i;
int sz = n * in->Bands;
unsigned char *p1 = in[0];
unsigned char *p2 = in[1];
for( i = 0; i < sz; i++ )
out[i] = p1[i] + p2[i];
}
\end{verbatim}
This can be made into a PIO function with:
\begin{verbatim}
int
add_uchar( IMAGE *i1, IMAGE *i2,
IMAGE *out )
{
IMAGE *invec[3];
/* Check parameters. We don't need to
* check that i1 and i2 are the same
* size, im_wrapmany() does that for
* us.
*/
if( i1->BandFmt != IM_BANDFMT_UCHAR ||
i1->Coding != IM_CODING_NONE ||
i2->BandFmt != IM_BANDFMT_UCHAR ||
i2->Coding != IM_CODING_NONE ||
i1->Bands != i2->Bands ) {
im_error( "add_uchar", "bad in" );
return( -1 );
}
/* Set fields in output image. As
* input image, but we want a USHORT.
*/
if( im_cp_desc( out, i1 ) )
return( -1 );
out->BandFmt = IM_BANDFMT_USHORT;
out->Bbits = IM_BBITS_SHORT;
/* Process! The first user-parameter
* is the number of bands involved.
* invec is a NULL-terminated array of
* input images.
*/
invec[0] = i1; invec[1] = i2;
invec[2] = NULL;
if( im_wrapmany( invec, out,
(im_wrapone_fn)add_buffer,
i1, NULL ) )
return( -1 );
return( 0 );
}
\end{verbatim}
\subsection{Region descriptors}
Regions are the next layer of abstraction above image descriptors. A region
is a small part of an image, held in memory ready for processing. A region
is defined as:
\begin{verbatim}
typedef struct {
Rect valid;
IMAGE *im;
... and some other private fields,
... used by VIPS for housekeeping
} REGION;
\end{verbatim}
\noindent
where \verb+valid+ holds the sub-area of image \verb+im+ that this region
represents, and \verb+Rect+ is defined as:
\begin{verbatim}
typedef struct {
int left, top;
int width, height;
} Rect;
\end{verbatim}
\noindent
two macros are available for \verb+Rect+ calculations:
\begin{verbatim}
int IM_RECT_RIGHT( Rect *r )
int IM_RECT_BOTTOM( Rect *r )
\end{verbatim}
\noindent
where \verb+IM_RECT_RIGHT()+ returns \verb+left+ + \verb+width+, and
\verb+IM_RECT_BOTTOM()+ returns \verb+top+ + \verb+height+. A small library
of C functions are also available for \verb+Rect+ algebra, see the manual
pages for \verb+im_rect_intersectrect()+.
Regions are created with \verb+im_region_create()+. This has type:
\begin{verbatim}
REGION *im_region_create( IMAGE *im )
\end{verbatim}
\noindent
\verb+im_region_create()+ returns a pointer to a new region structure,
or \verb+NULL+ on error. Regions returned by \verb+im_region_create()+
are blank --- they contain no image data and cannot be read from or written
to. See the next couple of sections for calls to fill regions with data.
Regions are destroyed with \verb+im_region_free()+. It has type:
\begin{verbatim}
int im_region_free( REGION *reg )
\end{verbatim}
\noindent
And, as usual, returns 0 on success and non-zero on error, setting
\verb+im_error()+. You must free all regions you create. If you close
an image without freeing all the regions defined on that image, the image is
just marked for future closure --- it is not actually closed until the final
region is freed. This behaviour helps to prevent dangling pointers, and it
is not difficult to make sure you free all regions --- see the examples below.
\subsection{Image input with regions}
Before you can read from a region, you need to call \verb+im_prepare()+
to fill the region with image data. It has type:
\begin{verbatim}
int im_prepare( REGION *reg, Rect *r )
\end{verbatim}
Area \verb+r+ of the image on which \verb+reg+ has been created is prepared
and attached to the region.
Exactly what this preparation involves depends upon the image --- it can
vary from simply adjusting some pointers, to triggering the evaluation of a
series of other functions. If it returns successfully, \verb+im_prepare()+
guarantees that all pixels within \verb+reg->valid+ may be accessed. Note
that this may be smaller or larger than \verb+r+, since \verb+im_prepare()+
clips \verb+r+ against the size of the image.
Programs can access image data in the region by calling the macro
\verb+IM_REGION_ADDR()+. It has type
\begin{verbatim}
char *IM_REGION_ADDR( REGION *reg,
int x, int y )
\end{verbatim}
Provided that point (x,y) lies inside \verb+reg->valid+,
\verb+IM_REGION_ADDR()+ returns a pointer to pel $(x,y)$. Adding to the result
of \verb+IM_REGION_ADDR()+ moves to the right along the line of pels, provided
you stay strictly within \verb+reg->valid+. Add \verb+IM_REGION_LSKIP()+
to move down a line, see below. \verb+IM_REGION_ADDR()+ has some other
useful features --- see the manual page.
Other macros are available to ease address calculation:
\begin{verbatim}
int IM_REGION_LSKIP( REGION *reg )
int IM_REGION_N_ELEMENTS( REGION *reg )
int IM_REGION_SIZEOF_LINE( REGION *reg )
\end{verbatim}
\noindent
These find the number of bytes to add to the result of \verb+IM_REGION_ADDR()+
to move down a line, the number of band elements across the region and the
number of bytes across the region.
\fref{fg:paverage} is a version of \verb+average()+ which uses
regions rather than WIO input. Two things: first, we should really be
using \verb+vips_sink()+, see \pref{sec:sequence}, to do the rectangle
algebra for us. Secondly, note that we call \verb+im_pincheck()+ rather
than \verb+im_incheck()+. \verb+im_pincheck()+ signals to the IO system
that you are a PIO-aware function, giving \verb+im_prepare()+ much more
flexibility in the sorts of preparation it can do. Also see the manual
pages for \verb+im_poutcheck()+ and \verb+im_piocheck()+.
\begin{fig2}
\begin{verbatim}
#include <stdio.h>
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/region.h>
int
average( IMAGE *im, double *out )
{
int total, i, y;
REGION *reg;
Rect area, *r;
/* Check im.
*/
if( im_pincheck( im ) )
return( -1 );
if( im->BandFmt != IM_BANDFMT_UCHAR || im->Coding != IM_CODING_NONE ) {
im_error( "average", "uncoded uchar images only" );
return( -1 );
}
/* Make a region on im which we can use for reading.
*/
if( !(reg = im_region_create( im )) )
return( -1 );
\end{verbatim}
\caption{First PIO average of image}
\label{fg:paverage}
\end{fig2}
\begin{fig2}
\begin{verbatim}
/* Move area over the image in 100x100 pel chunks.
* im_prepare() will clip against the edges of the image
* for us.
*/
total = 0;
r = &reg->valid;
area.width = 100; area.height = 100;
for( area.top = 0; area.top < im->Ysize; area.top += 100 )
for( area.left = 0; area.left < im->Xsize;
area.left += 100 ) {
/* Fill reg with pels.
*/
if( im_prepare( reg, &area ) ) {
/* We must free the region!
*/
im_region_free( reg );
return( -1 );
}
/* Loop over reg, adding to our total.
*/
for( y = r->top; y < IM_RECT_BOTTOM( r ); y++ ) {
unsigned char *p = IM_REGION_ADDR( reg, r->left, y );
for( i = 0; i < IM_REGION_N_ELEMENTS( reg ); i++ )
total += p[i];
}
}
/* Make sure we free the region.
*/
im_region_free( reg );
/* Find average.
*/
*out = (double) total / (IM_IMAGE_N_ELEMENTS( im ) * im->Ysize);
return( 0 );
}
\end{verbatim}
\caption{First PIO average of image (cont.)}
\end{fig2}
This version of \verb+average()+ can be called in exactly the same way as
the previous one, but this version has the great advantage of not needing
to have the whole of the input image available at once.
We can do one better than this --- if the image is being split into small
pieces, we can assign each piece to a separate thread of execution and get
parallelism. To support this splitting of tasks, VIPS has the notion of
a sequence.
\subsection{Splitting into sequences}
\label{sec:sequence}
A sequence comes in three parts: a start function, a processing function,
and a stop function. When VIPS starts up a new sequence, it runs the
start function. Start functions return sequence values: a void pointer
representing data local to this sequence. VIPS then repeatedly calls the
processing function, passing in the sequence value and a new piece of image
data for processing. Finally, when processing is complete, VIPS cleans up by
calling the stop function, passing in the sequence value as an argument. The
types look like this:
\begin{verbatim}
void *
(*start_fn)( IMAGE *out,
void *a, void *b )
int
(*process_fn)( REGION *reg,
void *seq, void *a, void *b )
int
(*stop_fn)( void *seq, void *a, void *b )
\end{verbatim}
\noindent
The values \verb+a+ and \verb+b+ are carried around by VIPS for your use.
For functions like \verb+average()+ which consume images but produce no image
output, VIPS provides \verb+vips_sink()+. This has type:
\begin{verbatim}
int vips_sink( VipsImage *in,
VipsStart start,
VipsGenerate generate,
VipsStop stop,
void *a, void *b )
\end{verbatim}
VIPS starts one or more sequences, runs one or more processing functions
over image \verb+in+ until all of \verb+in+ has been consumed, and then closes
all of the sequences down and returns. VIPS guarantees that the regions
the \verb+process_fn()+ is given will be complete and disjoint, that is,
every pixel in the image will be passed through exactly one sequence. To
make it possible for the sequences to each contribute to the result of the
function in an orderly manner, VIPS also guarantees that all start and stop
functions are mutually exclusive.
An example should make this clearer. This version of \verb+average()+
is very similar to the average function in the VIPS library --- it is only
missing polymorphism.
\begin{fig2}
\begin{verbatim}
#include <stdio.h>
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/region.h>
/* Start function for average(). We allocate a small piece of
* storage which this sequence will accumulate its total in. Our
* sequence value is just a pointer to this storage area.
*
* The first of the two pointers VIPS carries around for us is a
* pointer to the space where we store the grand total.
*/
static int *
average_start( IMAGE *out )
{
int *seq = IM_NEW( out, int );
if( !seq )
return( NULL );
*seq = 0;
return( seq );
}
/* Stop function for average(). Add the total which has
* accumulated in our sequence value to the grand total for
* the program.
*/
static int
average_stop( int *seq, int *gtotal )
{
/* Stop functions are mutually exclusive, so we can write
* to gtotal without clashing with any other stop functions.
*/
*gtotal += *seq;
return( 0 );
}
\end{verbatim}
\caption{Final PIO average of image}
\label{fg:p2average}
\end{fig2}
\begin{fig2}
\begin{verbatim}
/* Process function for average(). Total this region, and
* add that total to the sequence value.
*/
static int
average_process( REGION *reg, int *seq )
{
int total, i, y;
Rect *r = &reg->valid;
/* Get the appropriate part of the input image ready.
*/
if( im_prepare( reg, r ) )
return( -1 );
/* Loop over the region.
*/
total = 0;
for( y = r->top; y < IM_RECT_BOTTOM( r ); y++ ) {
unsigned char *p = IM_REGION_ADDR( reg, r->left, y );
for( i = 0; i < IM_REGION_N_ELEMENTS( reg ); i++ )
total += p[i];
}
/* Add to the total for this sequence.
*/
*seq += total;
return( 0 );
}
\end{verbatim}
\caption{Final PIO average of image (cont.)}
\end{fig2}
\begin{fig2}
\begin{verbatim}
/* Find average of image.
*/
int
average( IMAGE *im, double *out )
{
/* Accumulate grand total here.
*/
int gtotal = 0;
/* Prepare im for PIO reading.
*/
if( im_pincheck( im ) )
return( -1 );
/* Check it is the sort of thing we can process.
*/
if( im->BandFmt != IM_BANDFMT_UCHAR ||
im->Coding != IM_CODING_NONE ) {
im_error( "average", "uncoded uchar images only" );
return( -1 );
}
/* Loop over the image in pieces, and possibly in parallel.
*/
if( vips_sink( im,
average_start, average_process, average_stop,
&gtotal, NULL ) )
return( -1 );
/* Calculate average.
*/
*out = (double) gtotal / (IM_IMAGE_N_ELEMENTS( im ) * im->Ysize);
return( 0 );
}
\end{verbatim}
\caption{Final PIO average of image (cont.)}
\end{fig2}
There are a couple of variations on \verb+im_prepare()+: you can use
\verb+im_prepare_to()+ to force writing to a particular place, and
\verb+im_prepare_thread()+ to use threaded evaluation. See the man pages.
\subsection{Output to regions}
\label{sec:generate}
Regions are written to in just the same way they are read from --- by
writing to a pointer found with the \verb+IM_REGION_ADDR()+ macro.
\verb+vips_sink()+ does input --- \verb+im_generate()+ does output. It
has the same type as \verb+vips_sink()+:
\begin{verbatim}
int
im_generate( IMAGE *out,
void *(*start_fn)(),
int (*process_fn)(),
int (*stop_fn)(),
void *a, void *b )
\end{verbatim}
The region given to the process function is ready for output. Each time
the process function is called, it should fill in the pels in the region
it was given. Note that, unlike \verb+vips_sink()+, the areas the process
function is asked to produce are not guaranteed to be either disjoint or
complete. Again, VIPS may start up many process functions if it sees fit.
Here is \verb+invert()+, rewritten to use PIO. This piece of code makes use
of a pair of standard start and stop functions provided by the VIPS library:
\verb+im_start_one()+ and \verb+im_stop_one()+. They assume that the first
of the two user arguments to \verb+im_generate()+ is the input image. They are
defined as:
\begin{verbatim}
REGION *
im_start_one( IMAGE *out, IMAGE *in )
{
return( im_region_create( in ) );
}
\end{verbatim}
\noindent
and:
\begin{verbatim}
int
im_stop_one( REGION *seq )
{
return( im_region_free( seq ) );
}
\end{verbatim}
They are useful for simple functions which expect only one input
image. See the manual page for \verb+im_start_many()+ for many-input
functions.
\begin{fig2}
\begin{verbatim}
#include <stdio.h>
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/region.h>
/* Process function for invert(). Build the pixels in or
* from the appropriate pixels in ir.
*/
static int
invert_process( REGION *or, REGION *ir )
{
Rect *r = &or->valid;
int i, y;
/* Ask for the part of ir we need to make or. In this
* case, the two areas will be the same.
*/
if( im_prepare( ir, r ) )
return( -1 );
/* Loop over or writing pels calculated from ir.
*/
for( y = r->top; y < IM_RECT_BOTTOM( r ); y++ ) {
unsigned char *p = IM_REGION_ADDR( ir, r->left, y );
unsigned char *q = IM_REGION_ADDR( or, r->left, y );
for( i = 0; i < IM_REGION_N_ELEMENTS( or ); i++ )
q[i] = 255 - p[i];
}
/* Success!
*/
return( 0 );
}
\end{verbatim}
\caption{PIO invert}
\label{fg:p2invert}
\end{fig2}
\begin{fig2}
\begin{verbatim}
/* Invert an image.
*/
int
invert( IMAGE *in, IMAGE *out )
{
/* Check descriptors for PIO compatibility.
*/
if( im_piocheck( in, out ) )
return( -1 );
/* Check input image for compatibility with us.
*/
if( in->BandFmt != IM_BANDFMT_UCHAR || in->Coding != IM_CODING_NONE ) {
im_error( "invert", "uncoded uchar images only" );
return( -1 );
}
/* out inherits from in, as before.
*/
if( im_cp_desc( out, in ) )
return( -1 );
/* Set demand hints for out.
*/
if( im_demand_hint( out, IM_THINSTRIP, in, NULL ) )
return( -1 );
/* Build out in pieces, and possibly in parallel!
*/
if( im_generate( out,
im_start_one, invert_process, im_stop_one,
in, NULL ) )
return( -1 );
return( 0 );
}
\end{verbatim}
\caption{PIO invert (cont.)}
\end{fig2}
Functions have some choice about the way they write their output. Usually, they
should just write to the region they were given by \verb+im_generate()+. They
can, if they wish, set up the region for output to some other place. See
the manual page for \verb+im_region_region()+. See also the source for
\verb+im_copy()+ and \verb+im_extract()+ for examples of these tricks.
Note also the call to \verb+im_demand_hint()+. This function hints to the IO
system, suggesting the sorts of shapes of region this function is happiest
with. VIPS supports four basic shapes --- choosing the correct shape can
have a dramatic effect on the speed of your function. See the man page for
full details.
\subsection{Callbacks}
\label{sec:callback}
VIPS lets you attach callbacks to image descriptors. These are functions
you provide that VIPS will call when certain events occur. There are more
callbacks than are listed here: see the man page for full details.
\subsubsection{Close callbacks}
These callbacks are invoked just before an image is closed. They are useful
for freeing objects which are associated with the image. All callbacks are
triggered in the reverse order to the order in which they were attached. This
is sometimes important when freeing objects which contain pointers to
other objects. Close callbacks are guaranteed to be called, and to be called
exactly once.
Use \verb+im_add_close_callback()+ to add a close callback:
\begin{verbatim}
typedef int (*im_callback)( void *, void * )
int im_add_close_callback( IMAGE *,
im_callback_fn,
void *, void * )
\end{verbatim}
As with \verb+im_generate()+, the two \verb+void *+ pointers
are carried around for you by VIPS and may be used as your
function sees fit.
\subsubsection{Preclose callbacks}
Preclose callbacks are called before any shutdown has occured. Everything is
still alive and your callback can do anything to the image. Preclose callbacks
are guaranteed to be called, and to be called exactly once. See the manual
page for \verb+im_add_preclose_callback()+ for full details.
\subsubsection{Eval callbacks}
These are callbacks which are invoked periodically by VIPS during evaluation.
The callback has access to a struct containing information about the progress
of evaluation, useful for user-interfaces built on top of VIPS. See the
manual page for \verb+im_add_eval_callback()+ for full details.
\subsection{Memory allocation revisited}
When you are using PIO, memory allocation becomes rather more complicated than
it was before. There are essentially two types of memory which your function
might want to use for working space: memory which is associated with each
instance of your function (remember that two copies of you function may be
joined together in a pipeline and be running at the same time --- you can't
just use global variables), and memory which is local to each sequence
which VIPS starts on your argument image.
The first type, memory local to this function instance, typically holds
copies of any parameters passed to your image processing function, and links
to any read-only tables used by sequences which you run over the image. This
should be allocated in your main function.
The second type of memory, memory local to a sequence, should be allocated
in a start function. Because this space is private to a sequence, it may be
written to. Start and stop functions are guaranteed
to be single-threaded, so you may write to the function-local memory within
them.

View File

@ -1,114 +0,0 @@
\section{Introduction}
\mylabel{sec:ref}
{/bf
VIPS reference documentation is in the process of switching to gtkdoc.
Half-done manuals are distributed with VIPS, and they should be all done by
the next version.
In the meantime, this old and slightly outdated chapter has been left
unchanged from the previous version.
}
This chapter introduces the functions available in the VIPS image
processing library. For detailed information on particular functions,
refer to the UNIX on-line manual pages. Enter (for example):
\begin{verbatim}
example% man im_abs
\end{verbatim}
for information on the function \verb+im_abs()+.
All the comand-line vips operations will print help text too. For example:
\begin{verbatim}
example% vips im_extract
usage: vips im_extract input output
left top width height band
where:
input is of type "image"
output is of type "image"
left is of type "integer"
top is of type "integer"
width is of type "integer"
height is of type "integer"
band is of type "integer"
extract area/band, from package
"conversion"
flags: (PIO function)
(coordinate transformer)
(area operation)
(result can be cached)
vips: error calling function
im_run_command: too few arguments
\end{verbatim}
Once you have found a function you need to use, you can call it from a C
program (see \pref{sec:appl}), you can call
it from C++ or Python (see \pref{sec:cpp}), you can call
it from the \nip{} ((see the \emph{nip Manual}), or SIAM graphical
user-interfaces, or you can run it from the UNIX command line with the
\vips{} program. For example:
\begin{verbatim}
$ vips im_vips2tiff cam.v t1.tif none
$ vips im_tiff2vips t1.tif t2.v.v 0
$ vips im_equal cam.v t2.v t3.v
$ vips im_min t3.v
255
\end{verbatim}
VIPS may have been set up at your site with a set of links which call the
vips program for you. You may also be able to type:
\begin{verbatim}
$ im_vips2tiff cam.v t1.tif none
$ im_tiff2vips t1.tif t2.v.v 0
$ im_equal cam.v t2.v t3.v
$ im_min t3.v
\end{verbatim}
There are a few VIPS programs which you cannot run with \vips{}, either
because their arguments are a very strange, or because they are complete
mini-applications (like \verb+vips2dj+). These programs are listed in
table~\ref{tb:nondb}, see the man pages for full details.
\begin{tab2}
\centerline{
\begin{tabular}{|l|l|}
\hline
Name & Description \\
\hline
\texttt{binfile} & Read RAW image \\
\texttt{debugim} & Print an image pixel by pixel \\
\texttt{edvips} & Change fields in a VIPS header \\
\texttt{header} & Print fields from a VIPS header \\
\texttt{printlines} & Print an image a line at a time \\
\texttt{vips} & VIPS universal main program \\
\texttt{vips-7.14} & VIPS wrapper script \\
\texttt{find\_mosaic} & Analyse a set of images for overlaps \\
\texttt{mergeup} & Join a set of images together \\
\texttt{cooc\_features} & Calculate features of a co-occurence matrix \\
\texttt{cooc} & Calculate a co-occurence matrix \\
\texttt{glds\_features} & Calculate features of a grey-level
distribution matrix \\
\texttt{glds} & Calculate a grey-level distribution matrix \\
\texttt{simcontr} & Demonstrate simultaneous contrast \\
\texttt{sines} & Generate a sinusoidal test pattern \\
\texttt{spatres} & Generate a spatial resolution test pattern \\
\texttt{squares} & Generate some squares \\
\texttt{batch\_crop} & Crop a lot of images \\
\texttt{batch\_image\_convert} & File format convert a lot of images \\
\texttt{batch\_rubber\_sheet} & Warp a lot of images \\
\texttt{light\_correct} & Correct a set of images for shading errors \\
\texttt{mitsub} & Format a VIPS image for output to a Mitsubishi 3600 \\
\texttt{shrink\_width} & Shrink to a specific width \\
\texttt{vdump} & VIPS to mono Postscript \\
\texttt{vips2dj} & VIPS to high-quality colour Postscript \\
\hline
\end{tabular}
}
\caption{Miscellaneous programs}
\label{tb:nondb}
\end{tab2}

View File

@ -1,75 +0,0 @@
\section{The \texttt{VDisplay} class}
The \verb+VDisplay+ class is an abstraction over the VIPS \verb+im_col_display+
type which gives convenient and safe representation of VIPS display profiles.
VIPS display profiles are now mostly obsolete. You're better off using the
ICC colour management \verb+VImage+ member functions \verb+ICC_export()+ and
\verb+ICC_import()+.
\subsection{Constructors}
There are two constructors for \verb+VDisplay+:
\begin{verbatim}
VDisplay( const char *name );
VDisplay();
\end{verbatim}
The first form initialises the display from one of the standard VIPS display
types. For example:
\begin{verbatim}
VDisplay fred( "sRGB" );
VDisplay jim( "ultra2-20/2/98" );
\end{verbatim}
Makes \verb+fred+ a profile for making images in sRGB format, and \verb+jim+ a
profile representing my workstation display, as of 20/2/98. The second form
of constructor makes an uninitialised display.
\subsection{Projection functions}
A set of member functions of \verb+VDisplay+ provide read and write access to
the fields in the display.
\begin{verbatim}
char *name();
VDisplayType &type();
matrix &mat();
float &YCW();
float &xCW();
float &yCW();
float &YCR();
float &YCG();
float &YCB();
int &Vrwr();
int &Vrwg();
int &Vrwb();
float &Y0R();
float &Y0G();
float &Y0B();
float &gammaR();
float &gammaG();
float &gammaB();
float &B();
float &P();
\end{verbatim}
Where \verb+VDisplayType+ is defined as:
\begin{verbatim}
enum VDisplayType {
BARCO,
DUMB
};
\end{verbatim}
And \verb+matrix+ is defined as:
\begin{verbatim}
typedef float matrix[3][3];
\end{verbatim}
For a description of all the fields in a VIPS display profile, see the manual
page for \verb+im_XYZ2RGB()+.

View File

@ -1,76 +0,0 @@
\section{The \texttt{VError} class}
The \verb+VError+ class is the class thrown by the VIPS C++ API when an
error is detected. It is derived from \verb+std::exception+ in the usual way.
\subsection{Constructors}
There are two constructors for \verb+VError+:
\begin{verbatim}
VError( std::string str );
VError();
\end{verbatim}
The first form creates an error object initialised with the specified
string, the last form creates an empty error object.
\subsection{Projection functions}
A function gives access to the string held by \verb+VError+:
\begin{verbatim}
const char *what();
\end{verbatim}
You can also send to an \verb+ostream+.
\begin{verbatim}
std::ostream& operator<<(
std::ostream&, const error& );
\end{verbatim}
\subsection{Computing with \texttt{VError}}
Two member functions let you append elements to an error:
\begin{verbatim}
VError &app( std::string txt );
VError &app( const int i );
\end{verbatim}
For example:
\begin{verbatim}
VError wombat;
int n = 12;
wombat.app( "possum: no more than " ).
app( n ).app( " elements\n" );
throw( wombat );
\end{verbatim}
\noindent
will throw a \verb+VError+ with a diagnostic of:
\begin{verbatim}
possum: no more than 12 elements
\end{verbatim}
The member function \verb+perror()+ prints the error message to \verb+stdout+
and exits with a code of 1.
\begin{verbatim}
void perror( const char * );
void perror();
\end{verbatim}
\subsection{Convenience function}
The convenience function \verb+verror+ creates an \verb+VError+ with the
specified error string, and throws it. If you pass \verb+""+ for the string,
verror uses the contents of the VIPS error buffer instead.
\begin{verbatim}
extern void verror( std::string str = "" );
\end{verbatim}

View File

@ -1,372 +0,0 @@
\section{The \texttt{VImage} class}
The \verb+VImage+ class is a layer over the VIPS \verb+IMAGE+ type. It
automates almost all of the image creation and destruction issues that
complicate the C API, it automates error handling, and it provides a
convenient system for composing operations.
\subsection{Constructors}
There are two principal constructors for \verb+VImage+:
\begin{verbatim}
VImage::VImage( const char *name,
const char *mode = "r" );
VImage::VImage();
\end{verbatim}
The first form creates a new \verb+VImage+, linking it to the named file.
\verb+mode+ sets the mode for the file: it can take the following values:
\begin{description}
\item[\texttt{"r"}]
The named image file is opened read-only. This is the default mode.
\item[\texttt{"w"}]
A \verb+VImage+ is created which, when written to, will write pixels to disc
in the specified file. Any existing file of this name is deleted.
\item[\texttt{"t"}]
As the \verb'"w"' mode, but pixels written to the \verb+VImage+ will be saved
in a temporary memory buffer.
\item[\texttt{"p"}]
This creates a special `partial' image. Partial images represent
intermediate results, and are used to join VIPS operations together,
see~\pref{sec:compute}.
\item[\texttt{"rw"}]
As the \verb'"r"' mode, but the image is mapped into your address space
read-write. This mode is useful for paintbox-style
applications which need to directly modify an image. See \pref{sec:inplace}.
\end{description}
The second form of constructor is shorthand for:
\begin{verbatim}
VImage( "VImage:1", "p" )
\end{verbatim}
\noindent
It is used for representing intermediate results of computations.
Two further constructors are handy for wrapping \verb+VImage+ around existing
images.
\begin{verbatim}
VImage( void *buffer,
int width, int height, int bands,
TBandFmt format );
VImage( void *image );
\end{verbatim}
\noindent
The first constructor makes a \verb+VImage+ from an area of memory (perhaps
from another image processing system), and the second makes a \verb+VImage+
from an \verb+IMAGE+.
In both these two cases, the VIPS C++ API does not assume responsibility
for the resources: it's up to you to make sure the buffer is freed.
The Python interface adds the usual \verb+frombuffer+ and
\verb+fromstring+ methods.
\begin{verbatim}
VImage.fromstring (string,
width, height, bands, format) ->
VImage
\end{verbatim}
\begin{verbatim}
VImage.frombuffer (buffer,
width, height, bands, format) ->
VImage
\end{verbatim}
\noindent
Use \verb+fromstring+ to avoid worries about object lifetime, but you'll see a
lot of copies and high memory use. Use \verb+frombuffer+ for speed, but you
have to manage object lifetime yourself.
They are useful for moving images into VIPS from other image processing
libraries. There's also a utility function, \verb+vips_from_PIL_mode+, which
turns a PIL mode into a VIPS band, format, type triple.
\begin{verbatim}
VImage.vips_from_PIL_mode (mode) ->
(bands, format, type)
\end{verbatim}
See also \verb+tobuffer+ and \verb+tostring+ below.
\subsection{File conversion}
VIPS can read and write a number of different file formats. Information about
file format conversion is taken from the filename. For example:
\begin{verbatim}
VImage jim( "fred.jpg" );
\end{verbatim}
\noindent
This will decompress the file \verb+fred.jpg+ to a memory buffer, wrap a VIPS
image around the buffer and build a reference to it called \verb+jim+.
Options are passed to the file format converters embedded in the filename. For
example:
\begin{verbatim}
VImage out( "jen.tif:deflate", "w" );
\end{verbatim}
\noindent
Writing to the descriptor \verb+out+ will cause a TIFF image to be written to
disc with deflate compression.
See the manual page for \verb+im_open(3)+ for details of all the file formats
and conversions available. See the man page for \verb+VipsFormat(3)+ for a
lower-level API which lets you control more of the detail of reading and
writing data and is more suitable for large files.
\subsection{Projection functions}
A set of member functions of \verb+VImage+ provide access to the fields in
the header:
\begin{verbatim}
int Xsize();
int Ysize();
int Bands();
TBandFmt BandFmt();
TCoding Coding();
TType Type();
float Xres();
float Yres();
int Length();
TCompression Compression();
short Level();
int Xoffset();
int Yoffset();
\end{verbatim}
\noindent
Where \verb+TBandFmt+, \verb+TCoding+, \verb+TType+ and \verb+TCompression+
are \verb+enum+s for the types in the VIPS file header. See
section~\pref{sec:header} for an explanation of all of these fields.
Two functions give access to the filename and history
fields maintained by the VIPS IO system.
\begin{verbatim}
char *filename();
char *Hist();
\end{verbatim}
You can get and set extra metadata fields with \verb+meta_get()+ and
\verb+meta_set()+. They read and write \verb+GValue+ objects, see
\pref{sec:meta}.
\begin{verbatim}
void meta_set( const char *field, GValue *value );
void meta_get( const char *field, GValue *value_copy );
GType meta_get_type( const char *field );
\end{verbatim}
A set of convenience functions build on these two to provide accessors for
common types.
\begin{verbatim}
int meta_get_int( const char *field )
double meta_get_double( const char *field )
const char *meta_get_string( const char *field )
void *meta_get_area( const char *field )
void *meta_get_blob( const char *field, size_t *length )
void meta_set( const char *field, int value )
void meta_set( const char *field, double value )
void meta_set( const char *field, const char *value )
void meta_set( const char *field,
VCallback free_fn, void *value )
void meta_set( const char *field,
VCallback free_fn, void *value, size_t length )
\end{verbatim}
The \verb+image()+ member function provides access to the \verb+IMAGE+
descriptor underlying the C++ API. See the \pref{sec:appl} for details.
\begin{verbatim}
void *image();
\end{verbatim}
The \verb+data()+ member function returns a pointer to an array of pixel data
for the image.
\begin{verbatim}
void *data() const;
\end{verbatim}
\noindent
This can be very slow and use huge amounts of RAM.
The Python interface adds \verb+tobuffer+ and \verb+tostring+. These
operations call \verb+data()+ to generate the image pixels and then either
copy it and return the copy as a string, or wrap the pixels up as a Python
buffer object.
Use \verb+tostring+ to avoid worries about object lifetime, but you'll see a
lot of copies and high memory use. Use \verb+tobuffer+ for speed, but you
have to manage object lifetime yourself.
They are useful for moving images from VIPS into other image processing
libraries. There's also a utility function, \verb+PIL_mode_from_vips+, which
makes a PIL mode from a VIPS image.
\begin{verbatim}
VImage.PIL_mode_from_vips (vips-image) ->
mode
\end{verbatim}
See also \verb+frombuffer+ and \verb+fromstring+ above.
\subsection{Assignment}
\verb+VImage+ defines copy and assignment, with reference-counted,
pointer-style semantics. For example, if you write:
\begin{verbatim}
VImage fred( "fred.v" );
VImage jim( "jim.v" );
fred = jim;
\end{verbatim}
This will automatically close the file \verb+fred.v+, and make the variable
\verb+fred+ point to the image \verb+jim.v+ instead. Both \verb+jim+ and
\verb+fred+ now point to the same underlying image object.
Internally, a \verb+VImage+ object is just a pointer to a reference-counting
block, which in turn holds a pointer to the underlying VIPS \verb+IMAGE+ type.
You can therefore efficiently pass \verb+VImage+ objects to functions by
value, and return \verb+VImage+ objects as function results.
\subsection{Computing with \texttt{VImage}s}
\label{sec:compute}
All VIPS image processing operations are member functions of the \verb+VImage+
class. For example:
\begin{verbatim}
VImage fred( "fred.v" );
VImage jim( "jim.v" );
VImage result = fred.cos() + jim;
\end{verbatim}
Will apply \verb+im_costra()+ to \verb+fred.v+, making an image where each
pixel is the cosine of the corresponding pixel in \verb+fred.v+; then add that
image to \verb+jim.v+. Finally, the result will be held in \verb+result+.
VIPS is a demand-driven image processing system: when it computes expressions
like this, no actual pixels are calculated (although you can use the
projection functions on images --- \verb+result.BandFmt()+ for example). When
you finally write the result to a file (or use some operation that needs pixel
values, such as \verb+min()+, find minimum value), VIPS evaluates all of the
operations you have called to that point in parallel. If you have more than one
CPU in your machine, the load is spread over the available processors. This
means that there is no limit to the size of the images you can process.
\pref{sec:packages} lists all of the VIPS packages. These general
rules apply:
\begin{itemize}
\item
VIPS operation names become C++ member function names by dropping the
\verb+im_+ prefix, and if present, the \verb+tra+ postfix, the \verb+const+
postfix and the \verb+_vec+ postfix. For example, the
VIPS operation \verb+im_extract()+ becomes \verb+extract()+, and
\verb+im_costra()+ becomes \verb+cos()+.
\item
The \verb+VImage+ object to which you apply the member function is the first
input image, the member function returns the first output. If there is no
image input, the member is declared \verb+static+.
For example, \verb+im_project(3)+ returns two images. You can call it from
Python like this:
\begin{verbatim}
hout = VImage.VImage ()
vout = im.project (hout)
\end{verbatim}
\noindent
In other words, \verb+.project()+ writes the second result to the
\verb+VImage+ you pass as an argument.
\item
\verb+INTMASK+ and \verb+DOUBLEMASK+ types become \verb+VMask+ objects,
\verb+im_col_display+ types become \verb+VDisplay+ objects.
\item
Several C API functions can map to the same C++ API member. For example,
\verb+im_andimage+, \verb+im_andimage_vec+ and \verb+im_andimageconst+ all map
to the member \verb+andimage+. The API relies on overloading to
discriminate between these functions.
\end{itemize}
This part of the C++ API is generated automatically from the VIPS function
database, so it should all be up-to-date.
There are a set of arithmetic operators defined for your convenience. You can
generally write any arithmetic expression and include \verb+VImage+ in there.
\begin{verbatim}
VImage fred( "fred.v" );
VImage jim( "jim.v" );
Vimage v = int((fred + jim) / 2);
\end{verbatim}
\subsection{Writing results}
Once you have computed some result, you can write it to a file with the member
\verb+write()+. It takes the following forms:
\begin{verbatim}
VImage write( const char *name );
VImage write( VImage out );
VImage write();
\end{verbatim}
The first form simply writes the image to the named file. The second form
writes the image to the specified \verb+VImage+ object, for example:
\begin{verbatim}
VImage fred( "fred.v" );
VImage jim( "jim buffer", "t" );
Vimage v = (fred + 42).write( jim );
\end{verbatim}
\noindent
This creates a temporary memory buffer called \verb+jim+, and fills it with
the result of adding 42 to every pixel in \verb+fred.v+.
The final form of \verb+write()+ writes the image to a memory buffer, and
returns that.
\subsection{Type conversions}
Two type conversions are defined: you can cast \verb+VImage+ to a
\verb+VDMask+ and to a \verb+VIMask+.
\begin{verbatim}
operator VDMask();
operator VIMask();
\end{verbatim}
These operations are slow and need a lot of memory! Emergencies only.

View File

@ -1,95 +0,0 @@
\documentclass[a4paper,twocolumn,dvips]{book}
\usepackage[dvips=false,pdftex=false,vtex=false]{geometry}
\usepackage{ifpdf}
\ifpdf
\usepackage[pdftex]{graphicx,color}
\else
\usepackage{graphicx,color}
\fi
\usepackage{times}
\usepackage{fancyhdr}
\usepackage{ifthen}
\input{mydefs}
\fancyhead{} % clear all fields
\fancyhead[LE,RO]{\leftmark} % left-even, right-odd
\fancyhead[RE,LO]{VIPS Manual} % right-even, left-odd
\fancyfoot[LE,RO]{\thepage} % left-even, right-odd
\fancyfoot[RE,LO]{November 2014}
\begin{document}
\pagenumbering{roman}
\begin{titlepage}
\thispagestyle{empty}
\begin{center}
\huge
VIPS Manual\\
\large Version 7.42\\
\vspace{0.5in}
\large
John Cupitt,
Kirk Martinez\\
\end{center}
VIPS is currently (v. 7.42, November 2014) in an API transition. The API as
documented in 7.24 is still complete and supported and is the one you should
use. The 8.0 API is not yet done and may still change before completion.
% hmm ... must be a better way to get the quote at the bottom of the page
\vspace{5in}
This manual formatted \today
\setcounter{page}{1}
\end{titlepage}
% \blankpage
\tableofcontents
\thispagestyle{plain}
% \blankpage
\listoffigures
\thispagestyle{plain}
% \blankpage
\listoftables
\thispagestyle{plain}
% \blankpage
\pagenumbering{arabic}
\thispagestyle{plain}
\cfoot{}
\chapter{VIPS from C++ and Python}
\input{cppintro}
\input{fileformat}
\input{vimage}
\input{vmask}
\input{vdisplay}
\input{verror}
\chapter{VIPS for C programmers}
\input{applintro}
\input{iosys}
\input{func}
\input{object}
\input{format}
\input{interpolate}
\chapter{Writing VIPS operations}
\input{operintro}
\input{wio}
\input{pio}
\input{ipio}
\chapter{VIPS reference}
\input{refintro}
\input{packages}
\end{document}

View File

@ -1,175 +0,0 @@
\section{The \texttt{VMask} class}
The \verb+VMask+ class is an abstraction over the VIPS \verb+DOUBLEMASK+ and
\verb+INTMASK+ types which gives convenient and safe representation of
matrices.
\verb+VMask+ has two sub-classes, \verb+VIMask+ and \verb+VDMask+. These
represent matrices of integers and doubles respectively.
\subsection{Constructors}
There are four constructors for \verb+VIMask+ and \verb+VDMask+:
\begin{verbatim}
VIMask( int xsize, int ysize );
VIMask( int xsize, int ysize,
int scale, int offset, ... );
VIMask( int xsize, int ysize,
int scale, int offset,
std::vector<int> coeff );
VIMask( const char *name );
VIMask();
VDMask( int xsize, int ysize );
VDMask( int xsize, int ysize,
double scale, double offset, ... );
VDMask( int xsize, int ysize,
double scale, double offset,
std::vector<double> coeff );
VDMask( const char *name );
VDMask();
\end{verbatim}
The first form creates an empty matrix, with the specified dimensions;
the second form initialises a matrix from a varargs list; the third form
sets the matrix from a vector of coefficients; the fourth from the named file.
The final form makes a mask object with no contents yet.
The varargs constructors are not wrapped in Python --- use the vector
constructor instead. For example:
\begin{verbatim}
m = VMask.VIMask (3, 3, 1, 0,
[-1, -1, -1,
-1, 8, -1,
-1, -1, -1])
\end{verbatim}
\subsection{Projection functions}
A set of member functions of \verb+VIMask+ provide access to the fields in
the matrix:
\begin{verbatim}
int xsize() const;
int ysize() const;
int scale() const;
int offset() const;
const char *filename() const;
\end{verbatim}
\verb+VDMask+ is the same, except that the \verb+scale()+ and \verb+offset()+
members return \verb+double+. \verb+VMask+ allows all operations that are
common to \verb+VIMask+ and \verb+VDMask+.
\subsection{Assignment}
\verb+VMask+ defines copy and assignment with pointer-style
semantics. You can write stuff like:
\begin{verbatim}
VIMask fred( "mask" );
VMask jim;
jim = fred;
\end{verbatim}
This reads the file \verb+mask+, noting a pointer to the mask in \verb+fred+.
It then makes \verb+jim+ also point to it, so \verb+jim+ and \verb+fred+ are
sharing the same underlying matrix values.
Internally, a \verb+VMask+ object is just a pointer to a reference-counting
block, which in turn holds a pointer to the underlying VIPS \verb+MASK+ type.
You can therefore efficiently pass \verb+VMask+ objects to functions by
value, and return \verb+VMask+ objects as function results.
\subsection{Computing with \texttt{VMask}}
You can use \verb+[]+ to get at matrix elements, numbered left-to-right,
top-to-bottom. Alternatively, use \verb+()+ to address elements by $x,y$
position. For example:
\begin{verbatim}
VIMask fred( "mask" );
for( int i = 0; i < fred.xsize(); i++ )
fred[i] = 12;
\end{verbatim}
\noindent
will set the first line of the matrix to 12, and:
\begin{verbatim}
VDMask fred( "mask" );
for( int x = 0; x < fred.xsize(); x++ )
fred(x, x) = 12.0;
\end{verbatim}
\noindent
will set the leading diagonal to 12.
These don't work well in Python, so there's an extra member, \verb+get()+,
which will get an element by $x,y$ position.
\begin{verbatim}
x = mat.get (2, 4)
\end{verbatim}
See the member functions below for other operations on \verb+VMask+.
\subsection{\texttt{VIMask} operations}
The following operations are defined for \verb+VIMask+:
\begin{verbatim}
// Cast to VDMask and VImage
operator VDMask();
operator VImage();
// Build gaussian and log masks
static VIMask gauss( double, double );
static VIMask gauss_sep( double, double );
static VIMask log( double, double );
// Rotate
VIMask rotate45();
VIMask rotate90();
// Transpose, invert, join and multiply
VDMask trn() ;
VDMask inv();
VDMask cat( VDMask );
VDMask mul( VDMask );
\end{verbatim}
\subsection{\texttt{VDMask} operations}
The following operations are defined for \verb+VDMask+:
\begin{verbatim}
// Cast to VIMask and VImage
operator VIMask();
operator VImage();
// Build gauss and log masks
static VDMask gauss( double, double );
static VDMask log( double, double );
// Rotate
VDMask rotate45();
VDMask rotate90();
// Scale to intmask
VIMask scalei();
// Transpose, invert, join and multiply
VDMask trn();
VDMask inv();
VDMask cat( VDMask );
VDMask mul( VDMask );
\end{verbatim}
\subsection{Output of masks}
You can output masks with the usual \verb+<<+ operator.

View File

@ -1,363 +0,0 @@
\section{Programming WIO operations}
WIO is the style for you if you want ease of programming, or if your
algorithm must have the whole of the input image available at the same
time. For example, a Fourier transform operation is unable to produce any
output until it has seen the whole of the input image.
\subsection{Input from an image}
In WIO input, the whole of the image data is made available to the program
via the \verb+data+ field of the descriptor. To make an image ready for reading
in this style, programs should call \verb+im_incheck()+:
\begin{verbatim}
int im_incheck( IMAGE *im )
\end{verbatim}
\noindent
If it succeeds, it returns 0, if it fails, it returns non-zero and
sets \verb+im_error()+. On success, VIPS guarantees that all of the
user-accessible fields in the descriptor contain valid data, and that all
of the image data may be read by simply reading from the \verb+data+ field
(see below for an example). This will only work for images less than about
2GB in size.
VIPS has some simple macros to help address calculations on images:
\begin{verbatim}
int IM_IMAGE_SIZEOF_ELEMENT( IMAGE * )
int IM_IMAGE_SIZEOF_PEL( IMAGE * )
int IM_IMAGE_SIZEOF_LINE( IMAGE * )
int IM_IMAGE_N_ELEMENTS( IMAGE * )
char *IM_IMAGE_ADDR( IMAGE *,
int x, int y )
\end{verbatim}
\noindent
These macros calculate \verb+sizeof()+ a band element, a pel and a horizontal
line of pels. \verb+IM_IMAGE_N_ELEMENTS+ returns the number of band elements
across an image. \verb+IM_IMAGE_ADDR+ calculates the address of a pixel in an
image. If \verb+DEBUG+ is defined, it does bounds checking too.
\begin{fig2}
\begin{verbatim}
#include <stdio.h>
#include <stdlib.h>
#include <vips/vips.h>
int
average( IMAGE *im, double *out )
{
int x, y;
long total;
/* Prepare for reading.
*/
if( im_incheck( im ) )
return( -1 );
/* Check that this is the kind of image we can process.
*/
if( im->BandFmt != IM_BANDFMT_UCHAR ||
im->Coding != IM_CODING_NONE ) {
im_error( "average", "uncoded uchar images only" );
return( -1 );
}
/* Loop over the image, summing pixels.
*/
total = 0;
for( y = 0; y < im->Ysize; y++ ) {
unsigned char *p = (unsigned char *) IM_IMAGE_ADDR( im, 0, y );
for( x = 0; x < IM_IMAGE_N_ELEMENTS( im ); x++ )
total += p[x];
}
/* Calculate average.
*/
*out = (double) total /
(IM_IMAGE_N_ELEMENTS( im ) * im->Ysize));
/* Success!
*/
return( 0 );
}
\end{verbatim}
\caption{Find average of image}
\label{fg:average}
\end{fig2}
\fref{fg:average} is a simple WIO operation which calculates the
average of an unsigned char image. It will work for any size image, with any
number of bands. See~\pref{sec:poly} for techniques for making operations
which will work for any image type. This operation might be called from an
application with:
\begin{verbatim}
#include <stdio.h>
#include <stdlib.h>
#include <vips/vips.h>
void
find_average( char *name )
{
IMAGE *im;
double avg;
if( !(im = im_open( name, "r" )) ||
average( im, &avg ) ||
im_close( im ) )
error_exit( "failure!" );
printf( "Average of \"%s\" is %G\n",
name, avg );
}
\end{verbatim}
\noindent
When you write an image processing operation, you can test it by writing
a VIPS function descriptor and calling it from the \vips{} universal
main program, or from the \nip{} interface. See \pref{sec:appl}.
\subsection{Output to an image}
Before attempting WIO output, programs should call \verb+im_outcheck()+. It
has type:
\begin{verbatim}
int im_outcheck( IMAGE *im )
\end{verbatim}
\noindent
If \verb+im_outcheck()+ succeeds, VIPS guarantees that WIO output is sensible.
Programs should then set fields in the output descriptor to describe
the sort of image they wish to write (size, type, and so on) and call
\verb+im_setupout()+. It has type:
\begin{verbatim}
int im_setupout( IMAGE *im )
\end{verbatim}
\noindent
\verb+im_setupout()+ creates the output file or memory buffer, using the
size and type fields that were filled in by the program between the calls to
\verb+im_outcheck()+ and \verb+im_setupout()+, and gets it ready for writing.
Pels are written with \verb+im_writeline()+. This takes a y position (pel
(0,0) is in the top-left-hand corner of the image), a descriptor and a
pointer to a line of pels. It has type:
\begin{verbatim}
int im_writeline( int y,
IMAGE *im, unsigned char *pels )
\end{verbatim}
Two convenience functions are available to make this process slightly
easier. \verb+im_iocheck()+ is useful for programs which take one input
image and produce one image output. It simply calls \verb+im_incheck()+
and \verb+im_outcheck()+. It has type:
\begin{verbatim}
int im_iocheck( IMAGE *in, IMAGE *out )
\end{verbatim}
The second convenience function copies the fields describing size, type,
metadata and history from one image descriptor to another. It is useful when
the output
image will be similar in size and type to the input image. It has type:
\begin{verbatim}
int im_cp_desc( IMAGE *out, IMAGE *in )
\end{verbatim}
\noindent
There's also \verb+im_cp_descv()+, see the man page.
\begin{fig2}
\begin{verbatim}
#include <stdio.h>
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/util.h>
int
invert( IMAGE *in, IMAGE *out )
{
int x, y;
unsigned char *buffer;
/* Check images.
*/
if( im_iocheck( in, out ) )
return( -1 );
if( in->BandFmt != IM_BANDFMT_UCHAR || in->Coding != IM_CODING_NONE ) {
im_error( "invert", "uncoded uchar images only" );
return( -1 );
}
/* Make output image.
*/
if( im_cp_desc( out, in ) )
return( -1 );
if( im_setupout( out ) )
return( -1 );
/* Allocate a line buffer and make sure it will be freed correctly.
*/
if( !(buffer = IM_ARRAY( out,
IM_IMAGE_SIZEOF_LINE( in ), unsigned char )) )
return( -1 );
/* Loop over the image!
*/
for( y = 0; y < in->Ysize; y++ ) {
unsigned char *p = (unsigned char *) IM_IMAGE_ADDR( in, 0, y );
for( x = 0; x < IM_IMAGE_N_ELEMENTS( in ); x++ )
buffer[x] = 255 - p[x];
if( im_writeline( y, out, buffer ) )
return( -1 );
}
return( 0 );
}
\end{verbatim}
\caption{Invert an image}
\label{fg:invert}
\end{fig2}
\fref{fg:invert} is a WIO VIPS operation which finds the photographic
negative of an unsigned char image. See \pref{sec:malloc} for an explanation
of \verb+IM_ARRAY+. This operation might be called from an
application with:
\begin{verbatim}
#include <stdio.h>
#include <stdlib.h>
#include <vips/vips.h>
void
find_negative( char *inn, char *outn )
{
IMAGE *in, *out;
if( !(in = im_open( inn, "r" )) ||
!(out = im_open( outn, "w" )) ||
invert( in, out ) ||
im_updatehist( out, "invert" ) ||
im_close( in ) ||
im_close( out ) )
error_exit( "failure!" );
}
\end{verbatim}
See \pref{sec:history} for an explanation of the call to \verb+im_updatehist()+.
\subsection{Polymorphism}
\label{sec:poly}
Most image processing operations in the VIPS library can operate on
images of any type (\verb+IM_BANDFMT_UCHAR+, as in our examples above,
also \verb+IM_BANDFMT_UINT+ etc.). This is usually implemented with code
replication: the operation contains loops for processing every kind of image,
and when called, invokes the appropriate loop for the image it is given.
As an example, figure~\ref{fg:exp} calculates \verb+exp()+ for every pel
in an image. If the input image is \verb+double+, we write \verb+double+
output. If it is any other non-complex type, we write \verb+float+. If it
is complex, we flag an error (\verb+exp()+ of a complex number is fiddly).
The example uses an image type predicate, \verb+im_iscomplex()+. There are
a number of these predicate functions, see the manual page.
\begin{fig2}
\begin{verbatim}
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <vips/vips.h>
#include <vips/util.h>
/* Exponential transform.
*/
int
exptra( IMAGE *in, IMAGE *out )
{
int x, y;
unsigned char *buffer;
/* Check descriptors.
*/
if( im_iocheck( in, out ) )
return( -1 );
if( in->Coding != IM_CODING_NONE || im_iscomplex( in ) ) {
im_error( "exptra", "uncoded non-complex only" );
return( -1 );
}
/* Make output image.
*/
if( im_cp_desc( out, in ) )
return( -1 );
if( in->BandFmt != IM_BANDFMT_DOUBLE )
out->BandFmt = IM_BANDFMT_FLOAT;
if( im_setupout( out ) )
return( -1 );
\end{verbatim}
\caption{Calculate \texttt{exp()} for an image}
\label{fg:exp}
\end{fig2}
\begin{fig2}
\begin{verbatim}
/* Allocate a line buffer.
*/
if( !(buffer = IM_ARRAY( out, IM_IMAGE_SIZEOF_LINE( in ), unsigned char )) )
return( -1 );
/* Our inner loop, parameterised for both the input and output
* types. Note the use of `\', since macros have to be all on
* one line.
*/
#define loop(IN, OUT) { \
for( y = 0; y < in->Ysize; y++ ) { \
IN *p = (IN *) IM_IMAGE_ADDR( in, 0, y ); \
OUT *q = (OUT *) buffer; \
\
for( x = 0; x < IM_IMAGE_N_ELEMENTS( in ); x++ ) \
q[x] = exp( p[x] ); \
if( im_writeline( y, out, buffer ) ) \
return( -1 ); \
} \
}
/* Switch for all the types we can handle.
*/
switch( in->BandFmt ) {
case IM_BANDFMT_UCHAR: loop( unsigned char, float ); break;
case IM_BANDFMT_CHAR: loop( char, float ); break;
case IM_BANDFMT_USHORT:loop( unsigned short, float ); break;
case IM_BANDFMT_SHORT: loop( short, float ); break;
case IM_BANDFMT_UINT: loop( unsigned int, float ); break;
case IM_BANDFMT_INT: loop( int, float ); break;
case IM_BANDFMT_FLOAT: loop( float, float ); break;
case IM_BANDFMT_DOUBLE:loop( double, double ); break;
default:
im_error( "exptra", "internal error" );
return( -1 );
}
/* Success.
*/
return( 0 );
}
\end{verbatim}
\caption{Calculate \texttt{exp()} for an image (cont)}
\end{fig2}

View File

@ -402,6 +402,7 @@ vips_colour_build( VipsObject *object )
*/
if( vips_cast( extra_bands[i], &t1, out->BandFmt,
"shift", TRUE,
NULL ) ) {
g_object_unref( out );
return( -1 );

View File

@ -73,17 +73,34 @@ vips_scRGB2RGB16( VipsImage *in, VipsImage **out, ... )
return( vips_scRGB2sRGB( in, out, "depth", 16, NULL ) );
}
/* Do these two with a simple cast ... since we're just cast shifting, we can
* short-circuit the extra band processing in vips_colour_build().
*/
static int
vips_RGB162sRGB( VipsImage *in, VipsImage **out, ... )
{
if( vips_msb( in, out, NULL ) )
if( vips_cast( in, out, VIPS_FORMAT_UCHAR,
"shift", TRUE,
NULL ) )
return( -1 );
(*out)->Type = VIPS_INTERPRETATION_sRGB;
return( 0 );
}
static int
vips_sRGB2RGB16( VipsImage *in, VipsImage **out, ... )
{
if( vips_cast( in, out, VIPS_FORMAT_USHORT,
"shift", TRUE,
NULL ) )
return( -1 );
(*out)->Type = VIPS_INTERPRETATION_RGB16;
return( 0 );
}
/* Process the first @n bands with @fn, detach and reattach remaining bands.
*/
static int
@ -102,7 +119,9 @@ vips_process_n( const char *domain, VipsImage *in, VipsImage **out,
"n", in->Bands - n,
NULL ) ||
fn( t[0], &t[2], NULL ) ||
vips_cast( t[1], &t[3], t[2]->BandFmt, NULL ) ||
vips_cast( t[1], &t[3], t[2]->BandFmt,
"shift", TRUE,
NULL ) ||
vips_bandjoin2( t[2], t[3], out, NULL ) ) {
g_object_unref( scope );
return( -1 );

View File

@ -47,6 +47,8 @@
* - redone as a class
* 10/4/12
* - cast to uint now removes <0 values
* 11/2/15
* - add @shift option
*/
/*
@ -101,6 +103,7 @@ typedef struct _VipsCast {
VipsImage *in;
VipsBandFormat format;
gboolean shift;
int underflow; /* Number of underflows */
int overflow; /* Number of overflows */
@ -179,6 +182,33 @@ vips_cast_start( VipsImage *out, void *a, void *b )
return( seq );
}
/* Rightshift an integer type, ie. sizeof(ITYPE) > sizeof(OTYPE).
*/
#define VIPS_SHIFT_RIGHT( ITYPE, OTYPE ) { \
ITYPE * restrict p = (ITYPE *) in; \
OTYPE * restrict q = (OTYPE *) out; \
int n = ((int) sizeof( ITYPE ) << 3) - ((int) sizeof( OTYPE ) << 3); \
\
g_assert( sizeof( ITYPE ) > sizeof( OTYPE ) ); \
\
for( x = 0; x < sz; x++ ) \
q[x] = p[x] >> n; \
}
/* Leftshift an integer type, ie. sizeof(ITYPE) < sizeof(OTYPE). We need to
* copy the bottom bit up into the fresh new bits
*/
#define VIPS_SHIFT_LEFT( ITYPE, OTYPE ) { \
ITYPE * restrict p = (ITYPE *) in; \
OTYPE * restrict q = (OTYPE *) out; \
int n = ((int) sizeof( OTYPE ) << 3) - ((int) sizeof( ITYPE ) << 3); \
\
g_assert( sizeof( ITYPE ) < sizeof( OTYPE ) ); \
\
for( x = 0; x < sz; x++ ) \
q[x] = (p[x] << n) | (((p[x] & 1) << n) - (p[x] & 1)); \
}
/* Cast int types to an int type.
*/
#define VIPS_CLIP_INT_INT( ITYPE, OTYPE, VIPS_CLIP ) { \
@ -194,6 +224,21 @@ vips_cast_start( VipsImage *out, void *a, void *b )
} \
}
/* Int to int handling.
*/
#define VIPS_INT_INT( ITYPE, OTYPE, VIPS_CLIP ) { \
if( cast->shift && \
sizeof( ITYPE ) > sizeof( OTYPE ) ) { \
VIPS_SHIFT_RIGHT( ITYPE, OTYPE ); \
} \
else if( cast->shift ) { \
VIPS_SHIFT_LEFT( ITYPE, OTYPE ); \
} \
else { \
VIPS_CLIP_INT_INT( ITYPE, OTYPE, VIPS_CLIP ); \
} \
}
/* Cast float types to an int type.
*/
#define VIPS_CLIP_FLOAT_INT( ITYPE, OTYPE, VIPS_CLIP ) { \
@ -348,42 +393,42 @@ vips_cast_gen( VipsRegion *or, void *vseq, void *a, void *b,
switch( cast->in->BandFmt ) {
case VIPS_FORMAT_UCHAR:
BAND_SWITCH_INNER( unsigned char,
VIPS_CLIP_INT_INT,
VIPS_INT_INT,
VIPS_CLIP_REAL_FLOAT,
VIPS_CLIP_REAL_COMPLEX );
break;
case VIPS_FORMAT_CHAR:
BAND_SWITCH_INNER( signed char,
VIPS_CLIP_INT_INT,
VIPS_INT_INT,
VIPS_CLIP_REAL_FLOAT,
VIPS_CLIP_REAL_COMPLEX );
break;
case VIPS_FORMAT_USHORT:
BAND_SWITCH_INNER( unsigned short,
VIPS_CLIP_INT_INT,
VIPS_INT_INT,
VIPS_CLIP_REAL_FLOAT,
VIPS_CLIP_REAL_COMPLEX );
break;
case VIPS_FORMAT_SHORT:
BAND_SWITCH_INNER( signed short,
VIPS_CLIP_INT_INT,
VIPS_INT_INT,
VIPS_CLIP_REAL_FLOAT,
VIPS_CLIP_REAL_COMPLEX );
break;
case VIPS_FORMAT_UINT:
BAND_SWITCH_INNER( unsigned int,
VIPS_CLIP_INT_INT,
VIPS_INT_INT,
VIPS_CLIP_REAL_FLOAT,
VIPS_CLIP_REAL_COMPLEX );
break;
case VIPS_FORMAT_INT:
BAND_SWITCH_INNER( signed int,
VIPS_CLIP_INT_INT,
VIPS_INT_INT,
VIPS_CLIP_REAL_FLOAT,
VIPS_CLIP_REAL_COMPLEX );
break;
@ -499,6 +544,13 @@ vips_cast_class_init( VipsCastClass *class )
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsCast, format ),
VIPS_TYPE_BAND_FORMAT, VIPS_FORMAT_UCHAR );
VIPS_ARG_BOOL( class, "shift", 7,
_( "Shift" ),
_( "Shift integer values up and down" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsCast, shift ),
FALSE );
}
static void
@ -519,13 +571,22 @@ vips_castv( VipsImage *in, VipsImage **out, VipsBandFormat format, va_list ap )
* @format: format to convert to
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* @shift: integer values are shifted
*
* Convert @in to @format. You can convert between any pair of formats.
* Floats are truncated (not rounded). Out of range values are clipped.
*
* Casting from complex to real returns the real part.
*
* If @shift is %TRUE, integer values are shifted up and down. For example,
* casting from unsigned 8 bit to unsigned 16 bit would
* shift every value left by 8 bits. The bottom bit is copied into the new
* bits, so 255 would become 65535.
*
* See also: vips_scale(), vips_complexform(), vips_real(), vips_imag(),
* vips_cast_uchar().
* vips_cast_uchar(), vips_msb().
*
* Returns: 0 on success, -1 on error
*/

View File

@ -20,11 +20,11 @@ bin_SCRIPTS = \
batch_rubber_sheet \
batch_crop \
vipsprofile \
vips-7.42
vips-8.0
EXTRA_DIST = \
vipsprofile \
vips-7.42 \
vips-8.0 \
light_correct.in \
shrink_width.in \
batch_image_convert.in \

129
tools/vips-8.0 Executable file
View File

@ -0,0 +1,129 @@
#!/bin/bash
#
# Start script for VIPS
# need extended regexps, hence we insist on bash above
shopt -s extglob
# set -x
# name we were invoked as
bname=`basename $0`
# check args
if [[ $# < 1 ]]; then
echo "usage: $bname [command ...]"
echo "examples:"
echo " $bname man im_invert"
echo " $bname vips im_invert /pics/tmp/fred.jpg /pics/tmp/fred2.tif"
exit 1
fi
# prepend a path component to an environment variable
# be careful to avoid trailing : characters if the var is not defined, they
# can cause security problems
function prepend_var () {
# we have to use eval to do double indirection, I think
eval value="\$$1"
if [ "x$value" = x ]; then
export $1=$2
else
export $1=$2:$value
fi
}
# try to extract the prefix from a path to an executable
# eg. "/home/john/vips/bin/fred" -> "/home/john/vips"
function find_prefix () {
# try to canonicalise the path
ep_canon=$1
# relative path? prefix with pwd
if [ ${ep_canon:0:1} != "/" ]; then
ep_canon=`pwd`/$ep_canon
fi
# replace any "/./" with "/"
ep_canon=${ep_canon//\/.\//\/}
# any "xxx/../" can go
ep_canon=${ep_canon//+([^\/])\/..\//}
# trailing "xxx/.." can go
ep_canon=${ep_canon/%+([^\/])\/../}
# remove trailing "/bin/xxx" to get the prefix
ep_prefix=${ep_canon/%\/bin\/+([^\/])/}
# was there anything to remove in that final step? if not, the path
# must be wrong
if [ x$ep_prefix == x$ep_canon ]; then
return 1
fi
echo $ep_prefix;
return 0
}
# try to guess the install prefix from $0
function guess_prefix () {
# $0 is a file? must be us
if [ -f $0 ]; then
find_prefix $0
return
fi
# nope, extract program name from $0 and try looking along the
# searchpath for it
name=`basename $0`
fred=$PATH
while [ x$fred != x"" ]; do
path=${fred/:*/}/$name
fred=${fred/*([^:])?(:)/}
if [ -f $path ]; then
find_prefix $path
return
fi
done
# not found on path either ... give up!
return 1
}
prefix=`guess_prefix`;
if [ $? != 0 ]; then
echo "unable to find $0 from the file name, or from your PATH"
echo "either run directly, or add the install bin area to "
echo "your PATH"
exit 1
fi
export VIPSHOME=$prefix
# add VIPSHOME to man pages
prepend_var MANPATH $VIPSHOME/man
# add the VIPS lib area to the library path
case `uname` in
HPUX)
libvar=SHLIB_PATH
;;
Darwin)
libvar=DYLD_LIBRARY_PATH
;;
*)
libvar=LD_LIBRARY_PATH
;;
esac
prepend_var $libvar $VIPSHOME/lib
# add VIPS bin area to path
prepend_var PATH $VIPSHOME/bin
# run, passing in args we were passed
exec $*