start final push for vips 8
@ -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
@ -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
|
||||
|
||||
|
||||
|
||||
|
19
bootstrap.sh
@ -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 ...
|
||||
|
15
configure.ac
@ -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
|
||||
])
|
||||
|
||||
|
190
doc/Makefile.am
@ -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
@ -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
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
98
doc/libvips-docs.xml
Normal 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>
|
@ -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
|
@ -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
|
@ -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}
|
@ -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}
|
Before Width: | Height: | Size: 31 KiB |
@ -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 |
@ -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 |
Before Width: | Height: | Size: 26 KiB |
@ -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 |
@ -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.
|
||||
|
@ -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.
|
697
doc/src/func.tex
@ -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.
|
@ -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
|
@ -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()+.
|
@ -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.
|
||||
|
@ -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}
|
@ -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}
|
@ -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}
|
||||
|
@ -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}.
|
||||
|
@ -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}
|
854
doc/src/pio.tex
@ -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 = ®->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 = ®->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,
|
||||
>otal, 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.
|
||||
|
@ -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}
|
@ -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()+.
|
@ -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}
|
@ -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.
|
@ -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}
|
@ -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.
|
363
doc/src/wio.tex
@ -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}
|
@ -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 );
|
||||
|
@ -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 );
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
@ -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 $*
|